Search in sources :

Example 1 with RepoContext

use of com.google.gerrit.server.update.RepoContext 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;
        }
    }
    Collections.sort(commits, ReviewDbUtil.intKeyOrdering().reverse().onResultOf(c -> c.getPatchsetId()));
    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 : SubmoduleException(com.google.gerrit.server.git.SubmoduleException) OrmException(com.google.gwtorm.server.OrmException) GroupCollector(com.google.gerrit.server.git.GroupCollector) ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) LoggerFactory(org.slf4j.LoggerFactory) MissingObjectException(org.eclipse.jgit.errors.MissingObjectException) PatchSetApproval(com.google.gerrit.reviewdb.client.PatchSetApproval) MergeUtil(com.google.gerrit.server.git.MergeUtil) Map(java.util.Map) Context(com.google.gerrit.server.update.Context) Function(com.google.common.base.Function) ChangeMessage(com.google.gerrit.reviewdb.client.ChangeMessage) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit) Preconditions.checkState(com.google.common.base.Preconditions.checkState) Objects(java.util.Objects) List(java.util.List) LabelNormalizer(com.google.gerrit.server.git.LabelNormalizer) RefNames(com.google.gerrit.reviewdb.client.RefNames) MoreObjects.firstNonNull(com.google.common.base.MoreObjects.firstNonNull) BatchUpdateOp(com.google.gerrit.server.update.BatchUpdateOp) LabelId(com.google.gerrit.reviewdb.client.LabelId) Branch(com.google.gerrit.reviewdb.client.Branch) ChangeMessagesUtil(com.google.gerrit.server.ChangeMessagesUtil) Iterables(com.google.common.collect.Iterables) ReviewDb(com.google.gerrit.reviewdb.server.ReviewDb) CodeReviewRevWalk(com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk) Change(com.google.gerrit.reviewdb.client.Change) IncorrectObjectTypeException(org.eclipse.jgit.errors.IncorrectObjectTypeException) RepoContext(com.google.gerrit.server.update.RepoContext) HashMap(java.util.HashMap) SubmitRecord(com.google.gerrit.common.data.SubmitRecord) ArrayList(java.util.ArrayList) IntegrationException(com.google.gerrit.server.git.IntegrationException) Account(com.google.gerrit.reviewdb.client.Account) ChangeContext(com.google.gerrit.server.update.ChangeContext) REVIEWER(com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER) Project(com.google.gerrit.reviewdb.client.Project) Logger(org.slf4j.Logger) Preconditions.checkNotNull(com.google.common.base.Preconditions.checkNotNull) ProjectState(com.google.gerrit.server.project.ProjectState) ReviewDbUtil(com.google.gerrit.reviewdb.server.ReviewDbUtil) IOException(java.io.IOException) ApprovalsUtil(com.google.gerrit.server.ApprovalsUtil) ObjectId(org.eclipse.jgit.lib.ObjectId) ChangeUpdate(com.google.gerrit.server.notedb.ChangeUpdate) IdentifiedUser(com.google.gerrit.server.IdentifiedUser) PatchSet(com.google.gerrit.reviewdb.client.PatchSet) ProjectConfig(com.google.gerrit.server.git.ProjectConfig) Collections(java.util.Collections) Repository(org.eclipse.jgit.lib.Repository) ObjectId(org.eclipse.jgit.lib.ObjectId) ArrayList(java.util.ArrayList) CodeReviewRevWalk(com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk) PatchSet(com.google.gerrit.reviewdb.client.PatchSet) IncorrectObjectTypeException(org.eclipse.jgit.errors.IncorrectObjectTypeException) Change(com.google.gerrit.reviewdb.client.Change) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit) MissingObjectException(org.eclipse.jgit.errors.MissingObjectException) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with RepoContext

use of com.google.gerrit.server.update.RepoContext in project gerrit by GerritCodeReview.

the class NoteDbOnlyIT method updateChangeFailureRollsBackRefUpdate.

@Test
public void updateChangeFailureRollsBackRefUpdate() throws Exception {
    assume().that(notesMigration.fuseUpdates()).isTrue();
    PushOneCommit.Result r = createChange();
    Change.Id id = r.getChange().getId();
    String master = "refs/heads/master";
    String backup = "refs/backup/master";
    ObjectId master1 = getRef(master).get();
    assertThat(getRef(backup)).isEmpty();
    // Toy op that copies the value of refs/heads/master to refs/backup/master.
    BatchUpdateOp backupMasterOp = new BatchUpdateOp() {

        ObjectId newId;

        @Override
        public void updateRepo(RepoContext ctx) throws IOException {
            ObjectId oldId = ctx.getRepoView().getRef(backup).orElse(ObjectId.zeroId());
            newId = ctx.getRepoView().getRef(master).get();
            ctx.addRefUpdate(oldId, newId, backup);
        }

        @Override
        public boolean updateChange(ChangeContext ctx) {
            ctx.getUpdate(ctx.getChange().currentPatchSetId()).setChangeMessage("Backed up master branch to " + newId.name());
            return true;
        }
    };
    try (BatchUpdate bu = newBatchUpdate(batchUpdateFactory)) {
        bu.addOp(id, backupMasterOp);
        bu.execute();
    }
    // Ensure backupMasterOp worked.
    assertThat(getRef(backup)).hasValue(master1);
    assertThat(getMessages(id)).contains("Backed up master branch to " + master1.name());
    // Advance master by submitting the change.
    gApi.changes().id(id.get()).current().review(ReviewInput.approve());
    gApi.changes().id(id.get()).current().submit();
    ObjectId master2 = getRef(master).get();
    assertThat(master2).isNotEqualTo(master1);
    int msgCount = getMessages(id).size();
    try (BatchUpdate bu = newBatchUpdate(batchUpdateFactory)) {
        // This time, we attempt to back up master, but we fail during updateChange.
        bu.addOp(id, backupMasterOp);
        String msg = "Change is bad";
        bu.addOp(id, new BatchUpdateOp() {

            @Override
            public boolean updateChange(ChangeContext ctx) throws ResourceConflictException {
                throw new ResourceConflictException(msg);
            }
        });
        try {
            bu.execute();
            assert_().fail("expected ResourceConflictException");
        } catch (ResourceConflictException e) {
            assertThat(e).hasMessageThat().isEqualTo(msg);
        }
    }
    // If updateChange hadn't failed, backup would have been updated to master2.
    assertThat(getRef(backup)).hasValue(master1);
    assertThat(getMessages(id)).hasSize(msgCount);
}
Also used : RepoContext(com.google.gerrit.server.update.RepoContext) ChangeContext(com.google.gerrit.server.update.ChangeContext) ObjectId(org.eclipse.jgit.lib.ObjectId) Change(com.google.gerrit.reviewdb.client.Change) PushOneCommit(com.google.gerrit.acceptance.PushOneCommit) BatchUpdate(com.google.gerrit.server.update.BatchUpdate) ResourceConflictException(com.google.gerrit.extensions.restapi.ResourceConflictException) BatchUpdateOp(com.google.gerrit.server.update.BatchUpdateOp) Test(org.junit.Test) AbstractDaemonTest(com.google.gerrit.acceptance.AbstractDaemonTest)

Example 3 with RepoContext

use of com.google.gerrit.server.update.RepoContext in project gerrit by GerritCodeReview.

the class ConsistencyCheckerIT method mergeChange.

private ChangeControl mergeChange(ChangeControl ctl) throws Exception {
    final ObjectId oldId = getDestRef(ctl);
    final ObjectId newId = ObjectId.fromString(psUtil.current(db, ctl.getNotes()).getRevision().get());
    final String dest = ctl.getChange().getDest().get();
    try (BatchUpdate bu = newUpdate(adminId)) {
        bu.addOp(ctl.getId(), new BatchUpdateOp() {

            @Override
            public void updateRepo(RepoContext ctx) throws IOException {
                ctx.addRefUpdate(oldId, newId, dest);
            }

            @Override
            public boolean updateChange(ChangeContext ctx) throws OrmException {
                ctx.getChange().setStatus(Change.Status.MERGED);
                ctx.getUpdate(ctx.getChange().currentPatchSetId()).fixStatus(Change.Status.MERGED);
                return true;
            }
        });
        bu.execute();
    }
    return reload(ctl);
}
Also used : RepoContext(com.google.gerrit.server.update.RepoContext) ChangeContext(com.google.gerrit.server.update.ChangeContext) ObjectId(org.eclipse.jgit.lib.ObjectId) OrmException(com.google.gwtorm.server.OrmException) IOException(java.io.IOException) BatchUpdate(com.google.gerrit.server.update.BatchUpdate) BatchUpdateOp(com.google.gerrit.server.update.BatchUpdateOp)

Example 4 with RepoContext

use of com.google.gerrit.server.update.RepoContext in project gerrit by GerritCodeReview.

the class ConsistencyChecker method insertMergedPatchSet.

private void insertMergedPatchSet(final RevCommit commit, @Nullable final PatchSet.Id psIdToDelete, boolean reuseOldPsId) {
    ProblemInfo notFound = problem("No patch set found for merged commit " + commit.name());
    if (!user.get().isIdentifiedUser()) {
        notFound.status = Status.FIX_FAILED;
        notFound.outcome = "Must be called by an identified user to insert new patch set";
        return;
    }
    ProblemInfo insertPatchSetProblem;
    ProblemInfo deleteOldPatchSetProblem;
    if (psIdToDelete == null) {
        insertPatchSetProblem = problem(String.format("Expected merged commit %s has no associated patch set", commit.name()));
        deleteOldPatchSetProblem = null;
    } else {
        String msg = String.format("Expected merge commit %s corresponds to patch set %s," + " not the current patch set %s", commit.name(), psIdToDelete.get(), change().currentPatchSetId().get());
        // Maybe an identical problem, but different fix.
        deleteOldPatchSetProblem = reuseOldPsId ? null : problem(msg);
        insertPatchSetProblem = problem(msg);
    }
    List<ProblemInfo> currProblems = new ArrayList<>(3);
    currProblems.add(notFound);
    if (deleteOldPatchSetProblem != null) {
        currProblems.add(insertPatchSetProblem);
    }
    currProblems.add(insertPatchSetProblem);
    try {
        PatchSet.Id psId = (psIdToDelete != null && reuseOldPsId) ? psIdToDelete : ChangeUtil.nextPatchSetId(repo, change().currentPatchSetId());
        PatchSetInserter inserter = patchSetInserterFactory.create(ctl, psId, commit);
        try (BatchUpdate bu = newBatchUpdate()) {
            bu.setRepository(repo, rw, oi);
            if (psIdToDelete != null) {
                // Delete the given patch set ref. If reuseOldPsId is true,
                // PatchSetInserter will reinsert the same ref, making it a no-op.
                bu.addOp(ctl.getId(), new BatchUpdateOp() {

                    @Override
                    public void updateRepo(RepoContext ctx) throws IOException {
                        ctx.addRefUpdate(commit, ObjectId.zeroId(), psIdToDelete.toRefName());
                    }
                });
                if (!reuseOldPsId) {
                    bu.addOp(ctl.getId(), new DeletePatchSetFromDbOp(checkNotNull(deleteOldPatchSetProblem), psIdToDelete));
                }
            }
            bu.addOp(ctl.getId(), inserter.setValidate(false).setFireRevisionCreated(false).setNotify(NotifyHandling.NONE).setAllowClosed(true).setMessage("Patch set for merged commit inserted by consistency checker"));
            bu.addOp(ctl.getId(), new FixMergedOp(notFound));
            bu.execute();
        }
        ctl = changeControlFactory.controlFor(db.get(), inserter.getChange(), ctl.getUser());
        insertPatchSetProblem.status = Status.FIXED;
        insertPatchSetProblem.outcome = "Inserted as patch set " + psId.get();
    } catch (OrmException | IOException | UpdateException | RestApiException e) {
        warn(e);
        for (ProblemInfo pi : currProblems) {
            pi.status = Status.FIX_FAILED;
            pi.outcome = "Error inserting merged patch set";
        }
        return;
    }
}
Also used : RepoContext(com.google.gerrit.server.update.RepoContext) ProblemInfo(com.google.gerrit.extensions.common.ProblemInfo) ArrayList(java.util.ArrayList) PatchSet(com.google.gerrit.reviewdb.client.PatchSet) IOException(java.io.IOException) BatchUpdate(com.google.gerrit.server.update.BatchUpdate) OrmException(com.google.gwtorm.server.OrmException) UpdateException(com.google.gerrit.server.update.UpdateException) RestApiException(com.google.gerrit.extensions.restapi.RestApiException) BatchUpdateOp(com.google.gerrit.server.update.BatchUpdateOp)

Example 5 with RepoContext

use of com.google.gerrit.server.update.RepoContext in project gerrit by GerritCodeReview.

the class ChangeEditUtil method publish.

/**
   * Promote change edit to patch set, by squashing the edit into its parent.
   *
   * @param updateFactory factory for creating updates.
   * @param ctl the {@code ChangeControl} of the change to which the change edit belongs
   * @param edit change edit to publish
   * @param notify Notify handling that defines to whom email notifications should be sent after the
   *     change edit is published.
   * @param accountsToNotify Accounts that should be notified after the change edit is published.
   * @throws IOException
   * @throws OrmException
   * @throws UpdateException
   * @throws RestApiException
   */
public void publish(BatchUpdate.Factory updateFactory, ChangeControl ctl, final ChangeEdit edit, NotifyHandling notify, ListMultimap<RecipientType, Account.Id> accountsToNotify) throws IOException, OrmException, RestApiException, UpdateException {
    Change change = edit.getChange();
    try (Repository repo = gitManager.openRepository(change.getProject());
        ObjectInserter oi = repo.newObjectInserter();
        ObjectReader reader = oi.newReader();
        RevWalk rw = new RevWalk(reader)) {
        PatchSet basePatchSet = edit.getBasePatchSet();
        if (!basePatchSet.getId().equals(change.currentPatchSetId())) {
            throw new ResourceConflictException("only edit for current patch set can be published");
        }
        RevCommit squashed = squashEdit(rw, oi, edit.getEditCommit(), basePatchSet);
        PatchSet.Id psId = ChangeUtil.nextPatchSetId(repo, change.currentPatchSetId());
        PatchSetInserter inserter = patchSetInserterFactory.create(ctl, psId, squashed).setNotify(notify).setAccountsToNotify(accountsToNotify);
        StringBuilder message = new StringBuilder("Patch Set ").append(inserter.getPatchSetId().get()).append(": ");
        // Previously checked that the base patch set is the current patch set.
        ObjectId prior = ObjectId.fromString(basePatchSet.getRevision().get());
        ChangeKind kind = changeKindCache.getChangeKind(change.getProject(), rw, repo.getConfig(), prior, squashed);
        if (kind == ChangeKind.NO_CODE_CHANGE) {
            message.append("Commit message was updated.");
            inserter.setDescription("Edit commit message");
        } else {
            message.append("Published edit on patch set ").append(basePatchSet.getPatchSetId()).append(".");
        }
        try (BatchUpdate bu = updateFactory.create(db.get(), change.getProject(), ctl.getUser(), TimeUtil.nowTs())) {
            bu.setRepository(repo, rw, oi);
            bu.addOp(change.getId(), inserter.setDraft(change.getStatus() == Status.DRAFT || basePatchSet.isDraft()).setMessage(message.toString()));
            bu.addOp(change.getId(), new BatchUpdateOp() {

                @Override
                public void updateRepo(RepoContext ctx) throws Exception {
                    ctx.addRefUpdate(edit.getEditCommit().copy(), ObjectId.zeroId(), edit.getRefName());
                }
            });
            bu.execute();
        }
        indexer.index(db.get(), inserter.getChange());
    }
}
Also used : RepoContext(com.google.gerrit.server.update.RepoContext) ObjectId(org.eclipse.jgit.lib.ObjectId) PatchSet(com.google.gerrit.reviewdb.client.PatchSet) Change(com.google.gerrit.reviewdb.client.Change) RevWalk(org.eclipse.jgit.revwalk.RevWalk) BatchUpdate(com.google.gerrit.server.update.BatchUpdate) OrmException(com.google.gwtorm.server.OrmException) UpdateException(com.google.gerrit.server.update.UpdateException) AuthException(com.google.gerrit.extensions.restapi.AuthException) NoSuchChangeException(com.google.gerrit.server.project.NoSuchChangeException) RestApiException(com.google.gerrit.extensions.restapi.RestApiException) IOException(java.io.IOException) ResourceConflictException(com.google.gerrit.extensions.restapi.ResourceConflictException) Repository(org.eclipse.jgit.lib.Repository) ResourceConflictException(com.google.gerrit.extensions.restapi.ResourceConflictException) ObjectInserter(org.eclipse.jgit.lib.ObjectInserter) PatchSetInserter(com.google.gerrit.server.change.PatchSetInserter) ObjectReader(org.eclipse.jgit.lib.ObjectReader) RevCommit(org.eclipse.jgit.revwalk.RevCommit) ChangeKind(com.google.gerrit.extensions.client.ChangeKind) BatchUpdateOp(com.google.gerrit.server.update.BatchUpdateOp)

Aggregations

BatchUpdateOp (com.google.gerrit.server.update.BatchUpdateOp)5 RepoContext (com.google.gerrit.server.update.RepoContext)5 BatchUpdate (com.google.gerrit.server.update.BatchUpdate)4 OrmException (com.google.gwtorm.server.OrmException)4 IOException (java.io.IOException)4 ObjectId (org.eclipse.jgit.lib.ObjectId)4 Change (com.google.gerrit.reviewdb.client.Change)3 PatchSet (com.google.gerrit.reviewdb.client.PatchSet)3 ChangeContext (com.google.gerrit.server.update.ChangeContext)3 ResourceConflictException (com.google.gerrit.extensions.restapi.ResourceConflictException)2 RestApiException (com.google.gerrit.extensions.restapi.RestApiException)2 UpdateException (com.google.gerrit.server.update.UpdateException)2 Function (com.google.common.base.Function)1 MoreObjects.firstNonNull (com.google.common.base.MoreObjects.firstNonNull)1 Preconditions.checkNotNull (com.google.common.base.Preconditions.checkNotNull)1 Preconditions.checkState (com.google.common.base.Preconditions.checkState)1 Iterables (com.google.common.collect.Iterables)1 AbstractDaemonTest (com.google.gerrit.acceptance.AbstractDaemonTest)1 PushOneCommit (com.google.gerrit.acceptance.PushOneCommit)1 SubmitRecord (com.google.gerrit.common.data.SubmitRecord)1