LCOV - code coverage report
Current view: top level - server/restapi/change - ChangeEdits.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 176 179 98.3 %
Date: 2022-11-19 15:00:39 Functions: 35 35 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2014 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.restapi.change;
      16             : 
      17             : import static com.google.gerrit.server.project.ProjectCache.illegalState;
      18             : import static java.nio.charset.StandardCharsets.UTF_8;
      19             : 
      20             : import com.google.common.base.Strings;
      21             : import com.google.common.collect.ImmutableList;
      22             : import com.google.common.io.ByteStreams;
      23             : import com.google.gerrit.common.RawInputUtil;
      24             : import com.google.gerrit.entities.Change;
      25             : import com.google.gerrit.entities.Patch;
      26             : import com.google.gerrit.entities.PatchSet;
      27             : import com.google.gerrit.entities.Project;
      28             : import com.google.gerrit.extensions.api.changes.FileContentInput;
      29             : import com.google.gerrit.extensions.common.DiffWebLinkInfo;
      30             : import com.google.gerrit.extensions.common.EditInfo;
      31             : import com.google.gerrit.extensions.common.Input;
      32             : import com.google.gerrit.extensions.registration.DynamicMap;
      33             : import com.google.gerrit.extensions.restapi.AuthException;
      34             : import com.google.gerrit.extensions.restapi.BadRequestException;
      35             : import com.google.gerrit.extensions.restapi.BinaryResult;
      36             : import com.google.gerrit.extensions.restapi.ChildCollection;
      37             : import com.google.gerrit.extensions.restapi.DefaultInput;
      38             : import com.google.gerrit.extensions.restapi.IdString;
      39             : import com.google.gerrit.extensions.restapi.RawInput;
      40             : import com.google.gerrit.extensions.restapi.ResourceConflictException;
      41             : import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
      42             : import com.google.gerrit.extensions.restapi.Response;
      43             : import com.google.gerrit.extensions.restapi.RestCollectionCreateView;
      44             : import com.google.gerrit.extensions.restapi.RestCollectionDeleteMissingView;
      45             : import com.google.gerrit.extensions.restapi.RestCollectionModifyView;
      46             : import com.google.gerrit.extensions.restapi.RestModifyView;
      47             : import com.google.gerrit.extensions.restapi.RestReadView;
      48             : import com.google.gerrit.extensions.restapi.RestView;
      49             : import com.google.gerrit.server.WebLinks;
      50             : import com.google.gerrit.server.change.ChangeEditResource;
      51             : import com.google.gerrit.server.change.ChangeResource;
      52             : import com.google.gerrit.server.change.FileContentUtil;
      53             : import com.google.gerrit.server.change.FileInfoJson;
      54             : import com.google.gerrit.server.change.RevisionResource;
      55             : import com.google.gerrit.server.edit.ChangeEdit;
      56             : import com.google.gerrit.server.edit.ChangeEditJson;
      57             : import com.google.gerrit.server.edit.ChangeEditModifier;
      58             : import com.google.gerrit.server.edit.ChangeEditUtil;
      59             : import com.google.gerrit.server.git.GitRepositoryManager;
      60             : import com.google.gerrit.server.patch.PatchListNotAvailableException;
      61             : import com.google.gerrit.server.permissions.PermissionBackendException;
      62             : import com.google.gerrit.server.project.InvalidChangeOperationException;
      63             : import com.google.gerrit.server.project.ProjectCache;
      64             : import com.google.inject.Inject;
      65             : import com.google.inject.Provider;
      66             : import com.google.inject.Singleton;
      67             : import java.io.IOException;
      68             : import java.util.List;
      69             : import java.util.Optional;
      70             : import java.util.regex.Matcher;
      71             : import java.util.regex.Pattern;
      72             : import org.eclipse.jgit.lib.Repository;
      73             : import org.eclipse.jgit.revwalk.RevCommit;
      74             : import org.eclipse.jgit.revwalk.RevWalk;
      75             : import org.eclipse.jgit.util.Base64;
      76             : import org.kohsuke.args4j.Option;
      77             : 
      78             : @Singleton
      79             : public class ChangeEdits implements ChildCollection<ChangeResource, ChangeEditResource> {
      80             :   private final DynamicMap<RestView<ChangeEditResource>> views;
      81             :   private final Provider<Detail> detail;
      82             :   private final ChangeEditUtil editUtil;
      83             : 
      84             :   @Inject
      85             :   ChangeEdits(
      86             :       DynamicMap<RestView<ChangeEditResource>> views,
      87             :       Provider<Detail> detail,
      88         145 :       ChangeEditUtil editUtil) {
      89         145 :     this.views = views;
      90         145 :     this.detail = detail;
      91         145 :     this.editUtil = editUtil;
      92         145 :   }
      93             : 
      94             :   @Override
      95             :   public DynamicMap<RestView<ChangeEditResource>> views() {
      96           2 :     return views;
      97             :   }
      98             : 
      99             :   @Override
     100             :   public RestView<ChangeResource> list() {
     101           2 :     return detail.get();
     102             :   }
     103             : 
     104             :   @Override
     105             :   public ChangeEditResource parse(ChangeResource rsrc, IdString id)
     106             :       throws ResourceNotFoundException, AuthException, IOException {
     107           4 :     Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getNotes(), rsrc.getUser());
     108           4 :     if (!edit.isPresent()) {
     109           2 :       throw new ResourceNotFoundException(id);
     110             :     }
     111           4 :     return new ChangeEditResource(rsrc, edit.get(), id.get());
     112             :   }
     113             : 
     114             :   /**
     115             :    * Create handler that is activated when collection element is accessed but doesn't exist, e. g.
     116             :    * PUT request with a path was called but change edit wasn't created yet. Change edit is created
     117             :    * and PUT handler is called.
     118             :    */
     119             :   @Singleton
     120             :   public static class Create
     121             :       implements RestCollectionCreateView<ChangeResource, ChangeEditResource, FileContentInput> {
     122             :     private final Put putEdit;
     123             : 
     124             :     @Inject
     125         138 :     Create(Put putEdit) {
     126         138 :       this.putEdit = putEdit;
     127         138 :     }
     128             : 
     129             :     @Override
     130             :     public Response<Object> apply(
     131             :         ChangeResource resource, IdString id, FileContentInput fileContentInput)
     132             :         throws AuthException, BadRequestException, ResourceConflictException, IOException,
     133             :             PermissionBackendException {
     134           2 :       putEdit.apply(resource, id.get(), fileContentInput);
     135           2 :       return Response.none();
     136             :     }
     137             :   }
     138             : 
     139             :   @Singleton
     140             :   public static class DeleteFile
     141             :       implements RestCollectionDeleteMissingView<ChangeResource, ChangeEditResource, Input> {
     142             :     private final DeleteContent deleteContent;
     143             : 
     144             :     @Inject
     145         138 :     DeleteFile(DeleteContent deleteContent) {
     146         138 :       this.deleteContent = deleteContent;
     147         138 :     }
     148             : 
     149             :     @Override
     150             :     public Response<Object> apply(ChangeResource rsrc, IdString id, Input input)
     151             :         throws IOException, AuthException, BadRequestException, ResourceConflictException,
     152             :             PermissionBackendException {
     153           2 :       return deleteContent.apply(rsrc, id.get());
     154             :     }
     155             :   }
     156             : 
     157             :   // TODO(davido): Turn the boolean options to ChangeEditOption enum,
     158             :   // like it's already the case for ListChangesOption/ListGroupsOption
     159             :   public static class Detail implements RestReadView<ChangeResource> {
     160             :     private final ChangeEditUtil editUtil;
     161             :     private final ChangeEditJson editJson;
     162             :     private final FileInfoJson fileInfoJson;
     163             :     private final Revisions revisions;
     164             : 
     165             :     private String base;
     166             :     private boolean list;
     167             :     private boolean downloadCommands;
     168             : 
     169             :     @Option(name = "--base", metaVar = "revision-id")
     170             :     public void setBase(String base) {
     171           1 :       this.base = base;
     172           1 :     }
     173             : 
     174             :     @Option(name = "--list")
     175             :     public void setList(boolean list) {
     176           1 :       this.list = list;
     177           1 :     }
     178             : 
     179             :     @Option(name = "--download-commands")
     180             :     public void setDownloadCommands(boolean downloadCommands) {
     181           1 :       this.downloadCommands = downloadCommands;
     182           1 :     }
     183             : 
     184             :     @Inject
     185             :     Detail(
     186             :         ChangeEditUtil editUtil,
     187             :         ChangeEditJson editJson,
     188             :         FileInfoJson fileInfoJson,
     189           9 :         Revisions revisions) {
     190           9 :       this.editJson = editJson;
     191           9 :       this.editUtil = editUtil;
     192           9 :       this.fileInfoJson = fileInfoJson;
     193           9 :       this.revisions = revisions;
     194           9 :     }
     195             : 
     196             :     @Override
     197             :     public Response<EditInfo> apply(ChangeResource rsrc)
     198             :         throws AuthException, IOException, ResourceNotFoundException, ResourceConflictException,
     199             :             PermissionBackendException {
     200           9 :       Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getNotes(), rsrc.getUser());
     201           9 :       if (!edit.isPresent()) {
     202           4 :         return Response.none();
     203             :       }
     204             : 
     205           9 :       EditInfo editInfo = editJson.toEditInfo(edit.get(), downloadCommands);
     206           9 :       if (list) {
     207           1 :         PatchSet basePatchSet = null;
     208           1 :         if (base != null) {
     209           1 :           RevisionResource baseResource = revisions.parse(rsrc, IdString.fromDecoded(base));
     210           1 :           basePatchSet = baseResource.getPatchSet();
     211             :         }
     212             :         try {
     213           1 :           editInfo.files =
     214           1 :               fileInfoJson.getFileInfoMap(
     215           1 :                   rsrc.getChange(), edit.get().getEditCommit(), basePatchSet);
     216           0 :         } catch (PatchListNotAvailableException e) {
     217           0 :           throw new ResourceNotFoundException(e.getMessage());
     218           1 :         }
     219             :       }
     220           9 :       return Response.ok(editInfo);
     221             :     }
     222             :   }
     223             : 
     224             :   /**
     225             :    * Post to edit collection resource. Two different operations are supported:
     226             :    *
     227             :    * <ul>
     228             :    *   <li>Create non existing change edit
     229             :    *   <li>Restore path in existing change edit
     230             :    * </ul>
     231             :    *
     232             :    * The combination of two operations in one request is supported.
     233             :    */
     234             :   @Singleton
     235             :   public static class Post
     236             :       implements RestCollectionModifyView<ChangeResource, ChangeEditResource, Post.Input> {
     237           4 :     public static class Input {
     238             :       public String restorePath;
     239             :       public String oldPath;
     240             :       public String newPath;
     241             :     }
     242             : 
     243             :     private final ChangeEditModifier editModifier;
     244             :     private final GitRepositoryManager repositoryManager;
     245             : 
     246             :     @Inject
     247         142 :     Post(ChangeEditModifier editModifier, GitRepositoryManager repositoryManager) {
     248         142 :       this.editModifier = editModifier;
     249         142 :       this.repositoryManager = repositoryManager;
     250         142 :     }
     251             : 
     252             :     @Override
     253             :     public Response<Object> apply(ChangeResource resource, Post.Input postInput)
     254             :         throws AuthException, BadRequestException, IOException, ResourceConflictException,
     255             :             PermissionBackendException {
     256          18 :       Project.NameKey project = resource.getProject();
     257          18 :       try (Repository repository = repositoryManager.openRepository(project)) {
     258          18 :         if (isRestoreFile(postInput)) {
     259           1 :           editModifier.restoreFile(repository, resource.getNotes(), postInput.restorePath);
     260          18 :         } else if (isRenameFile(postInput)) {
     261           3 :           editModifier.renameFile(
     262           3 :               repository, resource.getNotes(), postInput.oldPath, postInput.newPath);
     263             :         } else {
     264          18 :           editModifier.createEdit(repository, resource.getNotes());
     265             :         }
     266           1 :       } catch (InvalidChangeOperationException e) {
     267           1 :         throw new ResourceConflictException(e.getMessage());
     268          18 :       }
     269          18 :       return Response.none();
     270             :     }
     271             : 
     272             :     private static boolean isRestoreFile(Post.Input postInput) {
     273          18 :       return postInput != null && !Strings.isNullOrEmpty(postInput.restorePath);
     274             :     }
     275             : 
     276             :     private static boolean isRenameFile(Post.Input postInput) {
     277          18 :       return postInput != null
     278           4 :           && !Strings.isNullOrEmpty(postInput.oldPath)
     279          18 :           && !Strings.isNullOrEmpty(postInput.newPath);
     280             :     }
     281             :   }
     282             : 
     283             :   /** Put handler that is activated when PUT request is called on collection element. */
     284             :   @Singleton
     285             :   public static class Put implements RestModifyView<ChangeEditResource, FileContentInput> {
     286         142 :     private static final Pattern BINARY_DATA_PATTERN =
     287         142 :         Pattern.compile("data:([\\w/.-]*);([\\w]+),(.*)");
     288             :     private static final String BASE64 = "base64";
     289             : 
     290             :     private final ChangeEditModifier editModifier;
     291             :     private final GitRepositoryManager repositoryManager;
     292             :     private final EditMessage editMessage;
     293             : 
     294             :     @Inject
     295             :     Put(
     296             :         ChangeEditModifier editModifier,
     297             :         GitRepositoryManager repositoryManager,
     298         142 :         EditMessage editMessage) {
     299         142 :       this.editModifier = editModifier;
     300         142 :       this.repositoryManager = repositoryManager;
     301         142 :       this.editMessage = editMessage;
     302         142 :     }
     303             : 
     304             :     @Override
     305             :     public Response<Object> apply(ChangeEditResource rsrc, FileContentInput fileContentInput)
     306             :         throws AuthException, BadRequestException, ResourceConflictException, IOException,
     307             :             PermissionBackendException {
     308           2 :       return apply(rsrc.getChangeResource(), rsrc.getPath(), fileContentInput);
     309             :     }
     310             : 
     311             :     public Response<Object> apply(
     312             :         ChangeResource rsrc, String path, FileContentInput fileContentInput)
     313             :         throws AuthException, BadRequestException, ResourceConflictException, IOException,
     314             :             PermissionBackendException {
     315             : 
     316          19 :       if (fileContentInput.content == null && fileContentInput.binary_content == null) {
     317           1 :         throw new BadRequestException("either content or binary_content is required");
     318             :       }
     319             : 
     320             :       RawInput newContent;
     321          19 :       if (fileContentInput.binary_content != null) {
     322           1 :         Matcher m = BINARY_DATA_PATTERN.matcher(fileContentInput.binary_content);
     323           1 :         if (m.matches() && BASE64.equals(m.group(2))) {
     324           1 :           newContent = RawInputUtil.create(Base64.decode(m.group(3)));
     325             :         } else {
     326           1 :           throw new BadRequestException("binary_content must be encoded as base64 data uri");
     327             :         }
     328           1 :       } else {
     329          19 :         newContent = fileContentInput.content;
     330             :       }
     331             : 
     332          19 :       if (Patch.COMMIT_MSG.equals(path) && fileContentInput.binary_content == null) {
     333           1 :         EditMessage.Input editMessageInput = new EditMessage.Input();
     334           1 :         editMessageInput.message =
     335           1 :             new String(ByteStreams.toByteArray(newContent.getInputStream()), UTF_8);
     336           1 :         return editMessage.apply(rsrc, editMessageInput);
     337             :       }
     338             : 
     339          19 :       if (Strings.isNullOrEmpty(path) || path.charAt(0) == '/') {
     340           1 :         throw new ResourceConflictException("Invalid path: " + path);
     341             :       }
     342             : 
     343          18 :       if (fileContentInput.fileMode != null) {
     344           1 :         if ((fileContentInput.fileMode != 100644) && (fileContentInput.fileMode != 100755)) {
     345           0 :           throw new BadRequestException(
     346             :               "file_mode ("
     347             :                   + fileContentInput.fileMode
     348             :                   + ") was invalid: supported values are 0, 644, or 755.");
     349             :         }
     350             :       }
     351             : 
     352          18 :       try (Repository repository = repositoryManager.openRepository(rsrc.getProject())) {
     353          18 :         editModifier.modifyFile(
     354          18 :             repository, rsrc.getNotes(), path, newContent, fileContentInput.fileMode);
     355           1 :       } catch (InvalidChangeOperationException e) {
     356           1 :         throw new ResourceConflictException(e.getMessage());
     357          18 :       }
     358          18 :       return Response.none();
     359             :     }
     360             :   }
     361             : 
     362             :   /**
     363             :    * Handler to delete a file.
     364             :    *
     365             :    * <p>This deletes the file from the repository completely. This is not the same as reverting or
     366             :    * restoring a file to its previous contents.
     367             :    */
     368             :   @Singleton
     369             :   public static class DeleteContent implements RestModifyView<ChangeEditResource, Input> {
     370             : 
     371             :     private final ChangeEditModifier editModifier;
     372             :     private final GitRepositoryManager repositoryManager;
     373             : 
     374             :     @Inject
     375         142 :     DeleteContent(ChangeEditModifier editModifier, GitRepositoryManager repositoryManager) {
     376         142 :       this.editModifier = editModifier;
     377         142 :       this.repositoryManager = repositoryManager;
     378         142 :     }
     379             : 
     380             :     @Override
     381             :     public Response<Object> apply(ChangeEditResource rsrc, Input input)
     382             :         throws AuthException, BadRequestException, ResourceConflictException, IOException,
     383             :             PermissionBackendException {
     384           2 :       return apply(rsrc.getChangeResource(), rsrc.getPath());
     385             :     }
     386             : 
     387             :     public Response<Object> apply(ChangeResource rsrc, String filePath)
     388             :         throws AuthException, BadRequestException, IOException, ResourceConflictException,
     389             :             PermissionBackendException {
     390           7 :       try (Repository repository = repositoryManager.openRepository(rsrc.getProject())) {
     391           6 :         editModifier.deleteFile(repository, rsrc.getNotes(), filePath);
     392           1 :       } catch (InvalidChangeOperationException e) {
     393           1 :         throw new ResourceConflictException(e.getMessage());
     394           6 :       }
     395           6 :       return Response.none();
     396             :     }
     397             :   }
     398             : 
     399             :   public static class Get implements RestReadView<ChangeEditResource> {
     400             :     private final FileContentUtil fileContentUtil;
     401             :     private final ProjectCache projectCache;
     402             :     private final GetMessage getMessage;
     403             : 
     404             :     @Option(
     405             :         name = "--base",
     406             :         aliases = {"-b"},
     407             :         usage = "whether to load the content on the base revision instead of the change edit")
     408             :     private boolean base;
     409             : 
     410             :     @Inject
     411           4 :     Get(FileContentUtil fileContentUtil, ProjectCache projectCache, GetMessage getMessage) {
     412           4 :       this.fileContentUtil = fileContentUtil;
     413           4 :       this.projectCache = projectCache;
     414           4 :       this.getMessage = getMessage;
     415           4 :     }
     416             : 
     417             :     @Override
     418             :     public Response<BinaryResult> apply(ChangeEditResource rsrc) throws AuthException, IOException {
     419             :       try {
     420           4 :         if (Patch.COMMIT_MSG.equals(rsrc.getPath())) {
     421           1 :           return getMessage.apply(rsrc.getChangeResource());
     422             :         }
     423             : 
     424           4 :         ChangeEdit edit = rsrc.getChangeEdit();
     425           4 :         Project.NameKey project = rsrc.getChangeResource().getProject();
     426           4 :         return Response.ok(
     427           4 :             fileContentUtil.getContent(
     428           4 :                 projectCache.get(project).orElseThrow(illegalState(project)),
     429           4 :                 base ? edit.getBasePatchSet().commitId() : edit.getEditCommit(),
     430           4 :                 rsrc.getPath(),
     431             :                 null));
     432           1 :       } catch (ResourceNotFoundException | BadRequestException e) {
     433           1 :         return Response.none();
     434             :       }
     435             :     }
     436             :   }
     437             : 
     438             :   @Singleton
     439             :   public static class GetMeta implements RestReadView<ChangeEditResource> {
     440             :     private final WebLinks webLinks;
     441             : 
     442             :     @Inject
     443         138 :     GetMeta(WebLinks webLinks) {
     444         138 :       this.webLinks = webLinks;
     445         138 :     }
     446             : 
     447             :     @Override
     448             :     public Response<FileInfo> apply(ChangeEditResource rsrc) {
     449           1 :       FileInfo r = new FileInfo();
     450           1 :       ChangeEdit edit = rsrc.getChangeEdit();
     451           1 :       Change change = edit.getChange();
     452           1 :       ImmutableList<DiffWebLinkInfo> links =
     453           1 :           webLinks.getDiffLinks(
     454           1 :               change.getProject().get(),
     455           1 :               change.getChangeId(),
     456           1 :               edit.getBasePatchSet().number(),
     457           1 :               edit.getBasePatchSet().refName(),
     458           1 :               rsrc.getPath(),
     459             :               0,
     460           1 :               edit.getRefName(),
     461           1 :               rsrc.getPath());
     462           1 :       r.webLinks = links.isEmpty() ? null : links;
     463           1 :       return Response.ok(r);
     464             :     }
     465             : 
     466           1 :     public static class FileInfo {
     467             :       public List<DiffWebLinkInfo> webLinks;
     468             :     }
     469             :   }
     470             : 
     471             :   @Singleton
     472             :   public static class EditMessage implements RestModifyView<ChangeResource, EditMessage.Input> {
     473           7 :     public static class Input {
     474             :       @DefaultInput public String message;
     475             :     }
     476             : 
     477             :     private final ChangeEditModifier editModifier;
     478             :     private final GitRepositoryManager repositoryManager;
     479             : 
     480             :     @Inject
     481         145 :     EditMessage(ChangeEditModifier editModifier, GitRepositoryManager repositoryManager) {
     482         145 :       this.editModifier = editModifier;
     483         145 :       this.repositoryManager = repositoryManager;
     484         145 :     }
     485             : 
     486             :     @Override
     487             :     public Response<Object> apply(ChangeResource rsrc, EditMessage.Input editMessageInput)
     488             :         throws AuthException, IOException, BadRequestException, ResourceConflictException,
     489             :             PermissionBackendException {
     490           7 :       if (editMessageInput == null || Strings.isNullOrEmpty(editMessageInput.message)) {
     491           1 :         throw new BadRequestException("commit message must be provided");
     492             :       }
     493             : 
     494           6 :       Project.NameKey project = rsrc.getProject();
     495           6 :       try (Repository repository = repositoryManager.openRepository(project)) {
     496           6 :         editModifier.modifyMessage(repository, rsrc.getNotes(), editMessageInput.message);
     497           1 :       } catch (InvalidChangeOperationException e) {
     498           1 :         throw new ResourceConflictException(e.getMessage());
     499           6 :       }
     500             : 
     501           6 :       return Response.none();
     502             :     }
     503             :   }
     504             : 
     505             :   public static class GetMessage implements RestReadView<ChangeResource> {
     506             :     private final GitRepositoryManager repoManager;
     507             :     private final ChangeEditUtil editUtil;
     508             : 
     509             :     @Option(
     510             :         name = "--base",
     511             :         aliases = {"-b"},
     512             :         usage = "whether to load the message on the base revision instead of the change edit")
     513             :     private boolean base;
     514             : 
     515             :     @Inject
     516          57 :     GetMessage(GitRepositoryManager repoManager, ChangeEditUtil editUtil) {
     517          57 :       this.repoManager = repoManager;
     518          57 :       this.editUtil = editUtil;
     519          57 :     }
     520             : 
     521             :     @Override
     522             :     public Response<BinaryResult> apply(ChangeResource rsrc)
     523             :         throws AuthException, IOException, ResourceNotFoundException {
     524           4 :       Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getNotes(), rsrc.getUser());
     525             :       String msg;
     526           4 :       if (edit.isPresent()) {
     527           4 :         if (base) {
     528           1 :           try (Repository repo = repoManager.openRepository(rsrc.getProject());
     529           1 :               RevWalk rw = new RevWalk(repo)) {
     530           1 :             RevCommit commit = rw.parseCommit(edit.get().getBasePatchSet().commitId());
     531           1 :             msg = commit.getFullMessage();
     532             :           }
     533             :         } else {
     534           4 :           msg = edit.get().getEditCommit().getFullMessage();
     535             :         }
     536             : 
     537           4 :         return Response.ok(
     538           4 :             BinaryResult.create(msg)
     539           4 :                 .setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
     540           4 :                 .base64());
     541             :       }
     542           1 :       throw new ResourceNotFoundException();
     543             :     }
     544             :   }
     545             : }

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