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

com.google.gerrit.server.restapi.change.PostReviewCopyApprovalsOp Maven / Gradle / Ivy

There is a newer version: 3.11.0-rc3
Show newest version
// Copyright (C) 2022 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.restapi.change;

import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.auto.factory.AutoFactory;
import com.google.auto.factory.Provided;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table.Cell;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.PatchSetApproval;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.approval.ApprovalCopier;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import java.io.IOException;
import java.util.Optional;

/**
 * Batch update operation that copy approvals that have been newly applied on outdated patch sets to
 * the follow-up patch sets if they are copyable and no non-copied approvals prevent the copying.
 *
 * 

Must be invoked after the batch update operation which applied new approvals on outdated patch * sets (e.g. after {@link PostReviewOp}. */ @AutoFactory public class PostReviewCopyApprovalsOp implements BatchUpdateOp { private final ApprovalCopier approvalCopier; private final PatchSetUtil patchSetUtil; private final PatchSet.Id patchSetId; private ChangeContext ctx; private ImmutableList followUpPatchSets; PostReviewCopyApprovalsOp( @Provided ApprovalCopier approvalCopier, @Provided PatchSetUtil patchSetUtil, PatchSet.Id patchSetId) { this.approvalCopier = approvalCopier; this.patchSetUtil = patchSetUtil; this.patchSetId = patchSetId; } @Override public boolean updateChange(ChangeContext ctx) throws IOException { if (ctx.getNotes().getCurrentPatchSet().id().equals(patchSetId)) { // the updated patch set is the current patch, there a no follow-up patch set to which new // approvals could be copied return false; } init(ctx); boolean dirty = false; ImmutableTable> newApprovals = ctx.getUpdate(patchSetId).getApprovals(); for (Cell> cell : newApprovals.cellSet()) { String label = cell.getRowKey(); Account.Id approverId = cell.getColumnKey(); PatchSetApproval.Key psaKey = PatchSetApproval.key(patchSetId, approverId, LabelId.create(label)); if (isRemoval(cell)) { if (removeCopies(psaKey)) { dirty = true; } continue; } PatchSet patchSet = patchSetUtil.get(ctx.getNotes(), patchSetId); PatchSetApproval psaOrig = cell.getValue().get(); // Target patch sets to which the approval is copyable. ImmutableList targetPatchSets = approvalCopier.forApproval( ctx.getNotes(), patchSet, psaKey.accountId(), psaKey.labelId().get(), psaOrig.value()); // Iterate over all follow-up patch sets, in patch set order. for (PatchSet.Id followUpPatchSetId : followUpPatchSets) { if (hasOverrideOf(followUpPatchSetId, psaKey)) { // a non-copied approval exists that overrides any copied approval // -> do not copy the approval to this patch set nor to any follow-up patch sets break; } if (targetPatchSets.contains(followUpPatchSetId)) { // The approval is copyable to the new patch set. if (hasCopyOfWithValue(followUpPatchSetId, psaKey, psaOrig.value())) { // a copy approval with the exact value already exists continue; } // add/update the copied approval on the target patch set PatchSetApproval copiedPatchSetApproval = psaOrig.copyWithPatchSet(followUpPatchSetId); ctx.getUpdate(followUpPatchSetId).putCopiedApproval(copiedPatchSetApproval); dirty = true; } else { // The approval is not copyable to the new patch set. if (hasCopyOf(followUpPatchSetId, psaKey)) { // a copy approval exists and should be removed removeCopy(followUpPatchSetId, psaKey); dirty = true; } } } } return dirty; } private void init(ChangeContext ctx) { this.ctx = ctx; // compute follow-up patch sets (sorted by patch set ID) this.followUpPatchSets = ctx.getNotes().getPatchSets().keySet().stream() .filter(psId -> psId.get() > patchSetId.get()) .collect(toImmutableList()); } /** * Whether the given cell entry from the approval table represents the removal of an approval. * * @param cell cell entry from the approval table * @return {@code true} if the approval is not set or the approval has {@code 0} as the value, * otherwise {@code false} */ private boolean isRemoval(Cell> cell) { return cell.getValue().isEmpty() || cell.getValue().get().value() == 0; } /** * Removes copies of the given approval from all follow-up patch sets. * * @param psaKey the key of the patch set approval for which copies should be removed from all * follow-up patch sets * @return whether any copy approval has been removed */ private boolean removeCopies(PatchSetApproval.Key psaKey) { boolean dirty = false; for (PatchSet.Id followUpPatchSet : followUpPatchSets) { if (hasCopyOf(followUpPatchSet, psaKey)) { removeCopy(followUpPatchSet, psaKey); } else { // Do not remove copy from this follow-up patch sets and also not from any further follow-up // patch sets (if the further follow-up patch sets have copies they are copies of a // non-copied approval on this follow-up patch set and hence those should not be removed). break; } } return dirty; } /** * Removes the copy approval with the given key from the given patch set. * * @param patchSet patch set from which the copy approval with the given key should be removed * @param psaKey the key of the patch set approval for which copies should be removed from the * given patch set */ private void removeCopy(PatchSet.Id patchSet, PatchSetApproval.Key psaKey) { ctx.getUpdate(patchSet) .removeCopiedApprovalFor( ctx.getIdentifiedUser().getRealUser().isIdentifiedUser() ? ctx.getIdentifiedUser().getRealUser().getAccountId() : null, psaKey.accountId(), psaKey.labelId().get()); } /** * Whether the given patch set has a copy approval with the given key. * * @param patchSetId the ID of the patch for which it should be checked whether it has a copy * approval with the given key * @param psaKey the key of the patch set approval */ private boolean hasCopyOf(PatchSet.Id patchSetId, PatchSetApproval.Key psaKey) { return ctx.getNotes().getApprovals().onlyCopied().get(patchSetId).stream() .anyMatch(psa -> areAccountAndLabelTheSame(psa.key(), psaKey)); } /** * Whether the given patch set has a copy approval with the given key and value. * * @param patchSetId the ID of the patch for which it should be checked whether it has a copy * approval with the given key and value * @param psaKey the key of the patch set approval */ private boolean hasCopyOfWithValue( PatchSet.Id patchSetId, PatchSetApproval.Key psaKey, short value) { return ctx.getNotes().getApprovals().onlyCopied().get(patchSetId).stream() .anyMatch(psa -> areAccountAndLabelTheSame(psa.key(), psaKey) && psa.value() == value); } /** * Whether the given patch set has a normal approval with the given key that overrides copy * approvals with that key. * * @param patchSetId the ID of the patch for which it should be checked whether it has a normal * approval with the given key that overrides copy approvals with that key * @param psaKey the key of the patch set approval */ private boolean hasOverrideOf(PatchSet.Id patchSetId, PatchSetApproval.Key psaKey) { return ctx.getNotes().getApprovals().onlyNonCopied().get(patchSetId).stream() .anyMatch(psa -> areAccountAndLabelTheSame(psa.key(), psaKey)); } private boolean areAccountAndLabelTheSame( PatchSetApproval.Key psaKey1, PatchSetApproval.Key psaKey2) { return psaKey1.accountId().equals(psaKey2.accountId()) && psaKey1.labelId().equals(psaKey2.labelId()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy