LCOV - code coverage report
Current view: top level - server/git - MergedByPushOp.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 66 79 83.5 %
Date: 2022-11-19 15:00:39 Functions: 8 11 72.7 %

          Line data    Source code
       1             : // Copyright (C) 2016 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.git;
      16             : 
      17             : import static java.util.Objects.requireNonNull;
      18             : 
      19             : import com.google.common.flogger.FluentLogger;
      20             : import com.google.gerrit.entities.Change;
      21             : import com.google.gerrit.entities.LabelId;
      22             : import com.google.gerrit.entities.PatchSet;
      23             : import com.google.gerrit.entities.PatchSetInfo;
      24             : import com.google.gerrit.entities.SubmissionId;
      25             : import com.google.gerrit.server.ChangeMessagesUtil;
      26             : import com.google.gerrit.server.PatchSetUtil;
      27             : import com.google.gerrit.server.config.SendEmailExecutor;
      28             : import com.google.gerrit.server.extensions.events.ChangeMerged;
      29             : import com.google.gerrit.server.mail.send.MergedSender;
      30             : import com.google.gerrit.server.mail.send.MessageIdGenerator;
      31             : import com.google.gerrit.server.notedb.ChangeUpdate;
      32             : import com.google.gerrit.server.patch.PatchSetInfoFactory;
      33             : import com.google.gerrit.server.update.BatchUpdateOp;
      34             : import com.google.gerrit.server.update.ChangeContext;
      35             : import com.google.gerrit.server.update.PostUpdateContext;
      36             : import com.google.gerrit.server.util.RequestScopePropagator;
      37             : import com.google.inject.Inject;
      38             : import com.google.inject.Provider;
      39             : import com.google.inject.assistedinject.Assisted;
      40             : import java.io.IOException;
      41             : import java.util.Optional;
      42             : import java.util.concurrent.ExecutorService;
      43             : import java.util.concurrent.Future;
      44             : import org.eclipse.jgit.lib.Constants;
      45             : import org.eclipse.jgit.lib.Repository;
      46             : import org.eclipse.jgit.revwalk.RevCommit;
      47             : import org.eclipse.jgit.revwalk.RevWalk;
      48             : 
      49             : /**
      50             :  * Operation to close a change on push.
      51             :  *
      52             :  * <p>When we find a change corresponding to a commit that is pushed to a branch directly, we close
      53             :  * the change. This class marks the change as merged, and sends out the email notification.
      54             :  */
      55             : public class MergedByPushOp implements BatchUpdateOp {
      56          11 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      57             : 
      58             :   public interface Factory {
      59             :     MergedByPushOp create(
      60             :         RequestScopePropagator requestScopePropagator,
      61             :         PatchSet.Id psId,
      62             :         @Assisted SubmissionId submissionId,
      63             :         @Assisted("refName") String refName,
      64             :         @Assisted("mergeResultRevId") String mergeResultRevId);
      65             :   }
      66             : 
      67             :   private final RequestScopePropagator requestScopePropagator;
      68             :   private final PatchSetInfoFactory patchSetInfoFactory;
      69             :   private final ChangeMessagesUtil cmUtil;
      70             :   private final MergedSender.Factory mergedSenderFactory;
      71             :   private final PatchSetUtil psUtil;
      72             :   private final ExecutorService sendEmailExecutor;
      73             :   private final ChangeMerged changeMerged;
      74             :   private final MessageIdGenerator messageIdGenerator;
      75             : 
      76             :   private final PatchSet.Id psId;
      77             :   private final SubmissionId submissionId;
      78             :   private final String refName;
      79             :   private final String mergeResultRevId;
      80             : 
      81             :   private Change change;
      82             :   private boolean correctBranch;
      83             :   private Provider<PatchSet> patchSetProvider;
      84             :   private PatchSet patchSet;
      85             :   private PatchSetInfo info;
      86             : 
      87             :   @Inject
      88             :   MergedByPushOp(
      89             :       PatchSetInfoFactory patchSetInfoFactory,
      90             :       ChangeMessagesUtil cmUtil,
      91             :       MergedSender.Factory mergedSenderFactory,
      92             :       PatchSetUtil psUtil,
      93             :       @SendEmailExecutor ExecutorService sendEmailExecutor,
      94             :       ChangeMerged changeMerged,
      95             :       MessageIdGenerator messageIdGenerator,
      96             :       @Assisted RequestScopePropagator requestScopePropagator,
      97             :       @Assisted PatchSet.Id psId,
      98             :       @Assisted SubmissionId submissionId,
      99             :       @Assisted("refName") String refName,
     100          11 :       @Assisted("mergeResultRevId") String mergeResultRevId) {
     101          11 :     this.patchSetInfoFactory = patchSetInfoFactory;
     102          11 :     this.cmUtil = cmUtil;
     103          11 :     this.mergedSenderFactory = mergedSenderFactory;
     104          11 :     this.psUtil = psUtil;
     105          11 :     this.sendEmailExecutor = sendEmailExecutor;
     106          11 :     this.changeMerged = changeMerged;
     107          11 :     this.messageIdGenerator = messageIdGenerator;
     108          11 :     this.requestScopePropagator = requestScopePropagator;
     109          11 :     this.submissionId = submissionId;
     110          11 :     this.psId = psId;
     111          11 :     this.refName = refName;
     112          11 :     this.mergeResultRevId = mergeResultRevId;
     113          11 :   }
     114             : 
     115             :   public String getMergedIntoRef() {
     116           0 :     return refName;
     117             :   }
     118             : 
     119             :   public MergedByPushOp setPatchSetProvider(Provider<PatchSet> patchSetProvider) {
     120           6 :     this.patchSetProvider = requireNonNull(patchSetProvider);
     121           6 :     return this;
     122             :   }
     123             : 
     124             :   @Override
     125             :   public boolean updateChange(ChangeContext ctx) throws IOException {
     126          11 :     change = ctx.getChange();
     127          11 :     correctBranch = refName.equals(change.getDest().branch());
     128          11 :     if (!correctBranch) {
     129           0 :       return false;
     130             :     }
     131             : 
     132          11 :     if (patchSetProvider != null) {
     133             :       // Caller might have also arranged for construction of a new patch set
     134             :       // that is not present in the old notes so we can't use PatchSetUtil.
     135           6 :       patchSet = patchSetProvider.get();
     136             :     } else {
     137          10 :       patchSet =
     138          10 :           requireNonNull(
     139          10 :               psUtil.get(ctx.getNotes(), psId),
     140           0 :               () -> String.format("patch set %s not found", psId));
     141             :     }
     142          11 :     info = getPatchSetInfo(ctx);
     143             : 
     144          11 :     ChangeUpdate update = ctx.getUpdate(psId);
     145          11 :     if (change.isMerged()) {
     146           0 :       return true;
     147             :     }
     148          11 :     change.setCurrentPatchSet(info);
     149          11 :     change.setStatus(Change.Status.MERGED);
     150          11 :     change.setSubmissionId(submissionId.toString());
     151             :     // we cannot reconstruct the submit records for when this change was
     152             :     // submitted, this is why we must fix the status and other details.
     153          11 :     update.fixStatusToMerged(submissionId);
     154          11 :     update.setCurrentPatchSet();
     155          11 :     if (change.isWorkInProgress()) {
     156           3 :       change.setWorkInProgress(false);
     157           3 :       update.setWorkInProgress(false);
     158             :     }
     159          11 :     StringBuilder msgBuf = new StringBuilder();
     160          11 :     msgBuf.append("Change has been successfully pushed");
     161          11 :     if (!refName.equals(change.getDest().branch())) {
     162           0 :       msgBuf.append(" into ");
     163           0 :       if (refName.startsWith(Constants.R_HEADS)) {
     164           0 :         msgBuf.append("branch ");
     165           0 :         msgBuf.append(Repository.shortenRefName(refName));
     166             :       } else {
     167           0 :         msgBuf.append(refName);
     168             :       }
     169             :     }
     170          11 :     msgBuf.append(".");
     171          11 :     cmUtil.setChangeMessage(update, msgBuf.toString(), ChangeMessagesUtil.TAG_MERGED);
     172          11 :     update.putApproval(LabelId.legacySubmit().get(), (short) 1);
     173          11 :     return true;
     174             :   }
     175             : 
     176             :   @Override
     177             :   public void postUpdate(PostUpdateContext ctx) {
     178          11 :     if (!correctBranch) {
     179           0 :       return;
     180             :     }
     181             :     @SuppressWarnings("unused") // Runnable already handles errors
     182          11 :     Future<?> possiblyIgnoredError =
     183          11 :         sendEmailExecutor.submit(
     184          11 :             requestScopePropagator.wrap(
     185          11 :                 new Runnable() {
     186             :                   @Override
     187             :                   public void run() {
     188             :                     try {
     189             :                       // The stickyApprovalDiff is always empty here since this is not supported
     190             :                       // for direct pushes.
     191          11 :                       MergedSender emailSender =
     192          11 :                           mergedSenderFactory.create(
     193          11 :                               ctx.getProject(),
     194          11 :                               psId.changeId(),
     195          11 :                               /* stickyApprovalDiff= */ Optional.empty());
     196          11 :                       emailSender.setFrom(ctx.getAccountId());
     197          11 :                       emailSender.setPatchSet(patchSet, info);
     198          11 :                       emailSender.setMessageId(
     199          11 :                           messageIdGenerator.fromChangeUpdate(ctx.getRepoView(), patchSet.id()));
     200          11 :                       emailSender.send();
     201           0 :                     } catch (Exception e) {
     202           0 :                       logger.atSevere().withCause(e).log(
     203             :                           "Cannot send email for submitted patch set %s", psId);
     204          11 :                     }
     205          11 :                   }
     206             : 
     207             :                   @Override
     208             :                   public String toString() {
     209           0 :                     return "send-email merged";
     210             :                   }
     211             :                 }));
     212             : 
     213          11 :     changeMerged.fire(
     214          11 :         ctx.getChangeData(change), patchSet, ctx.getAccount(), mergeResultRevId, ctx.getWhen());
     215          11 :   }
     216             : 
     217             :   private PatchSetInfo getPatchSetInfo(ChangeContext ctx) throws IOException {
     218          11 :     RevWalk rw = ctx.getRevWalk();
     219          11 :     RevCommit commit = rw.parseCommit(requireNonNull(patchSet).commitId());
     220          11 :     return patchSetInfoFactory.get(rw, commit, psId);
     221             :   }
     222             : }

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