All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.server.change.AddReviewersOp Maven / Gradle / Ivy

There is a newer version: 3.10.0-rc4
Show newest version
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.change;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.gerrit.extensions.client.ReviewerState.CC;
import static com.google.gerrit.extensions.client.ReviewerState.REVIEWER;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Streams;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.api.changes.RecipientType;
import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.mail.Address;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.extensions.events.ReviewerAdded;
import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.server.notedb.ReviewerStateInternal;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.Context;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Set;

public class AddReviewersOp implements BatchUpdateOp {
  public interface Factory {

    /**
     * Create a new op.
     *
     * 

Users may be added by account or by email addresses, as determined by {@code accountIds} * and {@code addresses}. The reviewer state for both accounts and email addresses is determined * by {@code state}. * * @param accountIds account IDs to add. * @param addresses email addresses to add. * @param state resulting reviewer state. * @param notify notification handling. * @param accountsToNotify additional accounts to notify. * @return batch update operation. */ AddReviewersOp create( Set accountIds, Collection

addresses, ReviewerState state, @Nullable NotifyHandling notify, ListMultimap accountsToNotify); } @AutoValue public abstract static class Result { public abstract ImmutableList addedReviewers(); public abstract ImmutableList
addedReviewersByEmail(); public abstract ImmutableList addedCCs(); public abstract ImmutableList
addedCCsByEmail(); static Builder builder() { return new AutoValue_AddReviewersOp_Result.Builder(); } @AutoValue.Builder abstract static class Builder { abstract Builder setAddedReviewers(Iterable addedReviewers); abstract Builder setAddedReviewersByEmail(Iterable
addedReviewersByEmail); abstract Builder setAddedCCs(Iterable addedCCs); abstract Builder setAddedCCsByEmail(Iterable
addedCCsByEmail); abstract Result build(); } } private final ApprovalsUtil approvalsUtil; private final PatchSetUtil psUtil; private final ReviewerAdded reviewerAdded; private final AccountCache accountCache; private final ProjectCache projectCache; private final AddReviewersEmail addReviewersEmail; private final NotesMigration migration; private final Set accountIds; private final Collection
addresses; private final ReviewerState state; private final NotifyHandling notify; private final ListMultimap accountsToNotify; // Unlike addedCCs, addedReviewers is a PatchSetApproval because the AddReviewerResult returned // via the REST API is supposed to include vote information. private List addedReviewers = ImmutableList.of(); private Collection
addedReviewersByEmail = ImmutableList.of(); private Collection addedCCs = ImmutableList.of(); private Collection
addedCCsByEmail = ImmutableList.of(); private Change change; private PatchSet patchSet; private Result opResult; @Inject AddReviewersOp( ApprovalsUtil approvalsUtil, PatchSetUtil psUtil, ReviewerAdded reviewerAdded, AccountCache accountCache, ProjectCache projectCache, AddReviewersEmail addReviewersEmail, NotesMigration migration, @Assisted Set accountIds, @Assisted Collection
addresses, @Assisted ReviewerState state, @Assisted @Nullable NotifyHandling notify, @Assisted ListMultimap accountsToNotify) { checkArgument(state == REVIEWER || state == CC, "must be %s or %s: %s", REVIEWER, CC, state); this.approvalsUtil = approvalsUtil; this.psUtil = psUtil; this.reviewerAdded = reviewerAdded; this.accountCache = accountCache; this.projectCache = projectCache; this.addReviewersEmail = addReviewersEmail; this.migration = migration; this.accountIds = accountIds; this.addresses = addresses; this.state = state; this.notify = notify; this.accountsToNotify = accountsToNotify; } void setPatchSet(PatchSet patchSet) { this.patchSet = requireNonNull(patchSet); } @Override public boolean updateChange(ChangeContext ctx) throws RestApiException, OrmException, IOException { change = ctx.getChange(); if (!accountIds.isEmpty()) { if (migration.readChanges() && state == CC) { addedCCs = approvalsUtil.addCcs( ctx.getNotes(), ctx.getUpdate(change.currentPatchSetId()), accountIds); } else { addedReviewers = approvalsUtil.addReviewers( ctx.getDb(), ctx.getNotes(), ctx.getUpdate(change.currentPatchSetId()), projectCache.checkedGet(change.getProject()).getLabelTypes(change.getDest()), change, accountIds); } } ImmutableList
addressesToAdd = ImmutableList.of(); ReviewerStateInternal internalState = ReviewerStateInternal.fromReviewerState(state); if (migration.readChanges()) { // TODO(dborowitz): This behavior should live in ApprovalsUtil or something, like addCcs does. ImmutableSet
existing = ctx.getNotes().getReviewersByEmail().byState(internalState); addressesToAdd = addresses.stream().filter(a -> !existing.contains(a)).collect(toImmutableList()); if (state == CC) { addedCCsByEmail = addressesToAdd; } else { addedReviewersByEmail = addressesToAdd; } for (Address a : addressesToAdd) { ctx.getUpdate(change.currentPatchSetId()).putReviewerByEmail(a, internalState); } } if (addedCCs.isEmpty() && addedReviewers.isEmpty() && addressesToAdd.isEmpty()) { return false; } checkAdded(); if (patchSet == null) { patchSet = requireNonNull(psUtil.current(ctx.getDb(), ctx.getNotes())); } return true; } private void checkAdded() { // Should only affect either reviewers or CCs, not both. But the logic in updateChange is // complex, so programmer error is conceivable. boolean addedAnyReviewers = !addedReviewers.isEmpty() || !addedReviewersByEmail.isEmpty(); boolean addedAnyCCs = !addedCCs.isEmpty() || !addedCCsByEmail.isEmpty(); checkState( !(addedAnyReviewers && addedAnyCCs), "should not have added both reviewers and CCs:\n" + "Arguments:\n" + " accountIds=%s\n" + " addresses=%s\n" + "Results:\n" + " addedReviewers=%s\n" + " addedReviewersByEmail=%s\n" + " addedCCs=%s\n" + " addedCCsByEmail=%s", accountIds, addresses, addedReviewers, addedReviewersByEmail, addedCCs, addedCCsByEmail); } @Override public void postUpdate(Context ctx) throws Exception { opResult = Result.builder() .setAddedReviewers(addedReviewers) .setAddedReviewersByEmail(addedReviewersByEmail) .setAddedCCs(addedCCs) .setAddedCCsByEmail(addedCCsByEmail) .build(); addReviewersEmail.emailReviewers( ctx.getUser().asIdentifiedUser(), change, Lists.transform(addedReviewers, PatchSetApproval::getAccountId), addedCCs, addedReviewersByEmail, addedCCsByEmail, notify, accountsToNotify, !change.isWorkInProgress()); if (!addedReviewers.isEmpty()) { List reviewers = addedReviewers .stream() .map(r -> accountCache.get(r.getAccountId())) .flatMap(Streams::stream) .collect(toList()); reviewerAdded.fire(change, patchSet, reviewers, ctx.getAccount(), ctx.getWhen()); } } public Result getResult() { checkState(opResult != null, "Batch update wasn't executed yet"); return opResult; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy