LCOV - code coverage report
Current view: top level - server/submit - SubmitStrategy.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 77 77 100.0 %
Date: 2022-11-19 15:00:39 Functions: 10 10 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2012 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.server.submit;
      16             : 
      17             : import static com.google.common.collect.ImmutableMap.toImmutableMap;
      18             : import static com.google.gerrit.server.project.ProjectCache.illegalState;
      19             : import static java.util.Objects.requireNonNull;
      20             : 
      21             : import com.google.common.collect.ImmutableList;
      22             : import com.google.common.collect.ImmutableMap;
      23             : import com.google.common.collect.Sets;
      24             : import com.google.gerrit.entities.BranchNameKey;
      25             : import com.google.gerrit.entities.Change;
      26             : import com.google.gerrit.entities.SubmissionId;
      27             : import com.google.gerrit.extensions.api.changes.SubmitInput;
      28             : import com.google.gerrit.extensions.client.SubmitType;
      29             : import com.google.gerrit.extensions.config.FactoryModule;
      30             : import com.google.gerrit.server.ChangeMessagesUtil;
      31             : import com.google.gerrit.server.GerritPersonIdent;
      32             : import com.google.gerrit.server.IdentifiedUser;
      33             : import com.google.gerrit.server.PatchSetUtil;
      34             : import com.google.gerrit.server.account.AccountCache;
      35             : import com.google.gerrit.server.approval.ApprovalsUtil;
      36             : import com.google.gerrit.server.change.LabelNormalizer;
      37             : import com.google.gerrit.server.change.RebaseChangeOp;
      38             : import com.google.gerrit.server.change.SetPrivateOp;
      39             : import com.google.gerrit.server.change.TestSubmitInput;
      40             : import com.google.gerrit.server.extensions.events.ChangeMerged;
      41             : import com.google.gerrit.server.git.CodeReviewCommit;
      42             : import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk;
      43             : import com.google.gerrit.server.git.GitRepositoryManager;
      44             : import com.google.gerrit.server.git.MergeTip;
      45             : import com.google.gerrit.server.git.MergeUtil;
      46             : import com.google.gerrit.server.git.MergeUtilFactory;
      47             : import com.google.gerrit.server.git.TagCache;
      48             : import com.google.gerrit.server.git.validators.OnSubmitValidators;
      49             : import com.google.gerrit.server.patch.PatchSetInfoFactory;
      50             : import com.google.gerrit.server.patch.SubmitWithStickyApprovalDiff;
      51             : import com.google.gerrit.server.project.ProjectCache;
      52             : import com.google.gerrit.server.project.ProjectConfig;
      53             : import com.google.gerrit.server.project.ProjectState;
      54             : import com.google.gerrit.server.query.change.InternalChangeQuery;
      55             : import com.google.gerrit.server.submit.MergeOp.CommitStatus;
      56             : import com.google.gerrit.server.update.BatchUpdate;
      57             : import com.google.inject.Inject;
      58             : import com.google.inject.Module;
      59             : import com.google.inject.Provider;
      60             : import com.google.inject.assistedinject.Assisted;
      61             : import java.util.ArrayList;
      62             : import java.util.Collection;
      63             : import java.util.Collections;
      64             : import java.util.HashSet;
      65             : import java.util.List;
      66             : import java.util.Optional;
      67             : import java.util.Set;
      68             : import org.eclipse.jgit.lib.PersonIdent;
      69             : import org.eclipse.jgit.revwalk.RevCommit;
      70             : import org.eclipse.jgit.revwalk.RevFlag;
      71             : 
      72             : /**
      73             :  * Base class that submit strategies must extend.
      74             :  *
      75             :  * <p>A submit strategy for a certain {@link SubmitType} defines how the submitted commits should be
      76             :  * merged.
      77             :  */
      78             : public abstract class SubmitStrategy {
      79             :   public static Module module() {
      80         152 :     return new FactoryModule() {
      81             :       @Override
      82             :       protected void configure() {
      83         152 :         factory(SubmitStrategy.Arguments.Factory.class);
      84         152 :         factory(EmailMerge.Factory.class);
      85         152 :       }
      86             :     };
      87             :   }
      88             : 
      89             :   static class Arguments {
      90             :     interface Factory {
      91             :       Arguments create(
      92             :           SubmitType submitType,
      93             :           BranchNameKey destBranch,
      94             :           CommitStatus commitStatus,
      95             :           CodeReviewRevWalk rw,
      96             :           IdentifiedUser caller,
      97             :           MergeTip mergeTip,
      98             :           RevFlag canMergeFlag,
      99             :           Set<RevCommit> alreadyAccepted,
     100             :           Set<CodeReviewCommit> incoming,
     101             :           SubmissionId submissionId,
     102             :           SubmitInput submitInput,
     103             :           SubmoduleCommits submoduleCommits,
     104             :           SubscriptionGraph subscriptionGraph,
     105             :           boolean dryrun);
     106             :     }
     107             : 
     108             :     final AccountCache accountCache;
     109             :     final ApprovalsUtil approvalsUtil;
     110             :     final ChangeMerged changeMerged;
     111             :     final ChangeMessagesUtil cmUtil;
     112             :     final EmailMerge.Factory mergedSenderFactory;
     113             :     final GitRepositoryManager repoManager;
     114             :     final LabelNormalizer labelNormalizer;
     115             :     final PatchSetInfoFactory patchSetInfoFactory;
     116             :     final PatchSetUtil psUtil;
     117             :     final ProjectCache projectCache;
     118             :     final PersonIdent serverIdent;
     119             :     final RebaseChangeOp.Factory rebaseFactory;
     120             :     final OnSubmitValidators.Factory onSubmitValidatorsFactory;
     121             :     final TagCache tagCache;
     122             :     final Provider<InternalChangeQuery> queryProvider;
     123             :     final ProjectConfig.Factory projectConfigFactory;
     124             :     final SetPrivateOp.Factory setPrivateOpFactory;
     125             :     final SubmitWithStickyApprovalDiff submitWithStickyApprovalDiff;
     126             : 
     127             :     final BranchNameKey destBranch;
     128             :     final CodeReviewRevWalk rw;
     129             :     final CommitStatus commitStatus;
     130             :     final IdentifiedUser caller;
     131             :     final MergeTip mergeTip;
     132             :     final RevFlag canMergeFlag;
     133             :     final Set<RevCommit> alreadyAccepted;
     134             :     final SubmissionId submissionId;
     135             :     final SubmitType submitType;
     136             :     final SubmitInput submitInput;
     137             :     final SubscriptionGraph subscriptionGraph;
     138             :     final SubmoduleCommits submoduleCommits;
     139             : 
     140             :     final ProjectState project;
     141             :     final MergeSorter mergeSorter;
     142             :     final RebaseSorter rebaseSorter;
     143             :     final MergeUtil mergeUtil;
     144             :     final boolean dryrun;
     145             : 
     146             :     @Inject
     147             :     Arguments(
     148             :         AccountCache accountCache,
     149             :         ApprovalsUtil approvalsUtil,
     150             :         ChangeMerged changeMerged,
     151             :         ChangeMessagesUtil cmUtil,
     152             :         EmailMerge.Factory mergedSenderFactory,
     153             :         GitRepositoryManager repoManager,
     154             :         LabelNormalizer labelNormalizer,
     155             :         MergeUtilFactory mergeUtilFactory,
     156             :         PatchSetInfoFactory patchSetInfoFactory,
     157             :         PatchSetUtil psUtil,
     158             :         @GerritPersonIdent PersonIdent serverIdent,
     159             :         ProjectCache projectCache,
     160             :         RebaseChangeOp.Factory rebaseFactory,
     161             :         OnSubmitValidators.Factory onSubmitValidatorsFactory,
     162             :         TagCache tagCache,
     163             :         Provider<InternalChangeQuery> queryProvider,
     164             :         ProjectConfig.Factory projectConfigFactory,
     165             :         SetPrivateOp.Factory setPrivateOpFactory,
     166             :         SubmitWithStickyApprovalDiff submitWithStickyApprovalDiff,
     167             :         @Assisted BranchNameKey destBranch,
     168             :         @Assisted CommitStatus commitStatus,
     169             :         @Assisted CodeReviewRevWalk rw,
     170             :         @Assisted IdentifiedUser caller,
     171             :         @Assisted MergeTip mergeTip,
     172             :         @Assisted RevFlag canMergeFlag,
     173             :         @Assisted Set<RevCommit> alreadyAccepted,
     174             :         @Assisted Set<CodeReviewCommit> incoming,
     175             :         @Assisted SubmissionId submissionId,
     176             :         @Assisted SubmitType submitType,
     177             :         @Assisted SubmitInput submitInput,
     178             :         @Assisted SubscriptionGraph subscriptionGraph,
     179             :         @Assisted SubmoduleCommits submoduleCommits,
     180          53 :         @Assisted boolean dryrun) {
     181          53 :       this.accountCache = accountCache;
     182          53 :       this.approvalsUtil = approvalsUtil;
     183          53 :       this.changeMerged = changeMerged;
     184          53 :       this.mergedSenderFactory = mergedSenderFactory;
     185          53 :       this.repoManager = repoManager;
     186          53 :       this.cmUtil = cmUtil;
     187          53 :       this.labelNormalizer = labelNormalizer;
     188          53 :       this.projectConfigFactory = projectConfigFactory;
     189          53 :       this.patchSetInfoFactory = patchSetInfoFactory;
     190          53 :       this.psUtil = psUtil;
     191          53 :       this.projectCache = projectCache;
     192          53 :       this.rebaseFactory = rebaseFactory;
     193          53 :       this.tagCache = tagCache;
     194          53 :       this.queryProvider = queryProvider;
     195          53 :       this.setPrivateOpFactory = setPrivateOpFactory;
     196          53 :       this.submitWithStickyApprovalDiff = submitWithStickyApprovalDiff;
     197             : 
     198          53 :       this.serverIdent = serverIdent;
     199          53 :       this.destBranch = destBranch;
     200          53 :       this.commitStatus = commitStatus;
     201          53 :       this.rw = rw;
     202          53 :       this.caller = caller;
     203          53 :       this.mergeTip = mergeTip;
     204          53 :       this.canMergeFlag = canMergeFlag;
     205          53 :       this.alreadyAccepted = alreadyAccepted;
     206          53 :       this.submissionId = submissionId;
     207          53 :       this.submitType = submitType;
     208          53 :       this.submitInput = submitInput;
     209          53 :       this.submoduleCommits = submoduleCommits;
     210          53 :       this.subscriptionGraph = subscriptionGraph;
     211          53 :       this.dryrun = dryrun;
     212             : 
     213          53 :       this.project =
     214          53 :           projectCache.get(destBranch.project()).orElseThrow(illegalState(destBranch.project()));
     215          53 :       this.mergeSorter =
     216             :           new MergeSorter(caller, rw, alreadyAccepted, canMergeFlag, queryProvider, incoming);
     217          53 :       this.rebaseSorter =
     218             :           new RebaseSorter(
     219             :               caller,
     220             :               rw,
     221          53 :               mergeTip.getInitialTip(),
     222             :               alreadyAccepted,
     223             :               canMergeFlag,
     224             :               queryProvider,
     225             :               incoming);
     226          53 :       this.mergeUtil = mergeUtilFactory.create(project);
     227          53 :       this.onSubmitValidatorsFactory = onSubmitValidatorsFactory;
     228          53 :     }
     229             :   }
     230             : 
     231             :   final Arguments args;
     232             : 
     233             :   private final Set<SubmitStrategyOp> submitStrategyOps;
     234             : 
     235          53 :   SubmitStrategy(Arguments args) {
     236          53 :     this.args = requireNonNull(args);
     237          53 :     this.submitStrategyOps = new HashSet<>();
     238          53 :   }
     239             : 
     240             :   /**
     241             :    * Returns the updated changed after this submit strategy has been executed.
     242             :    *
     243             :    * @return the updated changes after this submit strategy has been executed
     244             :    */
     245             :   public ImmutableMap<Change.Id, Change> getUpdatedChanges() {
     246          53 :     return submitStrategyOps.stream()
     247          53 :         .map(SubmitStrategyOp::getUpdatedChange)
     248          53 :         .filter(Optional::isPresent)
     249          53 :         .map(Optional::get)
     250          53 :         .collect(toImmutableMap(c -> c.getId(), c -> c));
     251             :   }
     252             : 
     253             :   /**
     254             :    * Add operations to a batch update that execute this submit strategy.
     255             :    *
     256             :    * <p>Guarantees exactly one op is added to the update for each change in the input set.
     257             :    *
     258             :    * @param bu batch update to add operations to.
     259             :    * @param toMerge the set of submitted commits that should be merged using this submit strategy.
     260             :    *     Implementations are responsible for ordering of commits, and will not modify the input in
     261             :    *     place.
     262             :    */
     263             :   public final void addOps(BatchUpdate bu, Set<CodeReviewCommit> toMerge) {
     264          53 :     List<SubmitStrategyOp> ops = buildOps(toMerge);
     265          53 :     Set<CodeReviewCommit> added = Sets.newHashSetWithExpectedSize(ops.size());
     266             : 
     267          53 :     for (SubmitStrategyOp op : ops) {
     268          53 :       added.add(op.getCommit());
     269          53 :     }
     270             : 
     271             :     // First add ops for any implicitly merged changes.
     272          53 :     List<CodeReviewCommit> difference = new ArrayList<>(Sets.difference(toMerge, added));
     273          53 :     Collections.reverse(difference);
     274          53 :     for (CodeReviewCommit c : difference) {
     275          15 :       Change.Id id = c.change().getId();
     276          15 :       bu.addOp(id, args.setPrivateOpFactory.create(false, null));
     277          15 :       ImplicitIntegrateOp implicitIntegrateOp = new ImplicitIntegrateOp(args, c);
     278          15 :       bu.addOp(id, implicitIntegrateOp);
     279          15 :       maybeAddTestHelperOp(bu, id);
     280          15 :       this.submitStrategyOps.add(implicitIntegrateOp);
     281          15 :     }
     282             : 
     283             :     // Then ops for explicitly merged changes
     284          53 :     for (SubmitStrategyOp op : ops) {
     285          53 :       bu.addOp(op.getId(), args.setPrivateOpFactory.create(false, null));
     286          53 :       bu.addOp(op.getId(), op);
     287          53 :       maybeAddTestHelperOp(bu, op.getId());
     288          53 :       this.submitStrategyOps.add(op);
     289          53 :     }
     290          53 :   }
     291             : 
     292             :   private void maybeAddTestHelperOp(BatchUpdate bu, Change.Id changeId) {
     293          53 :     if (args.submitInput instanceof TestSubmitInput) {
     294           8 :       bu.addOp(changeId, new TestHelperOp(changeId, args));
     295             :     }
     296          53 :   }
     297             : 
     298             :   protected abstract ImmutableList<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge);
     299             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750