LCOV - code coverage report
Current view: top level - server/group/db - GroupConfigCommitMessage.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 43 43 100.0 %
Date: 2022-11-19 15:00:39 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2018 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.group.db;
      16             : 
      17             : import com.google.common.collect.ImmutableSet;
      18             : import com.google.common.collect.Sets;
      19             : import com.google.common.collect.Streams;
      20             : import com.google.gerrit.entities.InternalGroup;
      21             : import java.util.Optional;
      22             : import java.util.Set;
      23             : import java.util.StringJoiner;
      24             : import java.util.function.BiFunction;
      25             : import java.util.function.Function;
      26             : import java.util.stream.Stream;
      27             : import org.eclipse.jgit.revwalk.FooterKey;
      28             : 
      29             : /**
      30             :  * A parsable commit message for a NoteDb commit of a group.
      31             :  *
      32             :  * <p>For group creations, it's sufficient to simply call the constructor of this class. For
      33             :  * updates, {@link #setOriginalGroup(InternalGroup)} has to be called as well.
      34             :  */
      35             : class GroupConfigCommitMessage {
      36         152 :   static final FooterKey FOOTER_ADD_MEMBER = new FooterKey("Add");
      37         152 :   static final FooterKey FOOTER_REMOVE_MEMBER = new FooterKey("Remove");
      38         152 :   static final FooterKey FOOTER_ADD_GROUP = new FooterKey("Add-group");
      39         152 :   static final FooterKey FOOTER_REMOVE_GROUP = new FooterKey("Remove-group");
      40             : 
      41             :   private final AuditLogFormatter auditLogFormatter;
      42             :   private final InternalGroup updatedGroup;
      43         152 :   private Optional<InternalGroup> originalGroup = Optional.empty();
      44             : 
      45         152 :   GroupConfigCommitMessage(AuditLogFormatter auditLogFormatter, InternalGroup updatedGroup) {
      46         152 :     this.auditLogFormatter = auditLogFormatter;
      47         152 :     this.updatedGroup = updatedGroup;
      48         152 :   }
      49             : 
      50             :   public void setOriginalGroup(InternalGroup originalGroup) {
      51         152 :     this.originalGroup = Optional.of(originalGroup);
      52         152 :   }
      53             : 
      54             :   public String create() {
      55         152 :     String summaryLine = originalGroup.isPresent() ? "Update group" : "Create group";
      56             : 
      57         152 :     StringJoiner footerJoiner = new StringJoiner("\n", "\n\n", "");
      58         152 :     footerJoiner.setEmptyValue("");
      59         152 :     Streams.concat(
      60         152 :             Streams.stream(getFooterForRename()),
      61         152 :             getFootersForMemberModifications(),
      62         152 :             getFootersForSubgroupModifications())
      63         152 :         .sorted()
      64         152 :         .forEach(footerJoiner::add);
      65         152 :     String footer = footerJoiner.toString();
      66             : 
      67         152 :     return summaryLine + footer;
      68             :   }
      69             : 
      70             :   private Optional<String> getFooterForRename() {
      71         152 :     if (!originalGroup.isPresent()) {
      72         152 :       return Optional.empty();
      73             :     }
      74             : 
      75         152 :     String originalName = originalGroup.get().getName();
      76         152 :     String newName = updatedGroup.getName();
      77         152 :     if (originalName.equals(newName)) {
      78         152 :       return Optional.empty();
      79             :     }
      80           4 :     return Optional.of("Rename from " + originalName + " to " + newName);
      81             :   }
      82             : 
      83             :   private Stream<String> getFootersForMemberModifications() {
      84         152 :     return getFooters(
      85             :         InternalGroup::getMembers,
      86             :         AuditLogFormatter::getParsableAccount,
      87             :         FOOTER_ADD_MEMBER,
      88             :         FOOTER_REMOVE_MEMBER);
      89             :   }
      90             : 
      91             :   private Stream<String> getFootersForSubgroupModifications() {
      92         152 :     return getFooters(
      93             :         InternalGroup::getSubgroups,
      94             :         AuditLogFormatter::getParsableGroup,
      95             :         FOOTER_ADD_GROUP,
      96             :         FOOTER_REMOVE_GROUP);
      97             :   }
      98             : 
      99             :   private <T> Stream<String> getFooters(
     100             :       Function<InternalGroup, Set<T>> getElements,
     101             :       BiFunction<AuditLogFormatter, T, String> toParsableString,
     102             :       FooterKey additionFooterKey,
     103             :       FooterKey removalFooterKey) {
     104         152 :     Set<T> oldElements = originalGroup.map(getElements).orElseGet(ImmutableSet::of);
     105         152 :     Set<T> newElements = getElements.apply(updatedGroup);
     106             : 
     107         152 :     Function<T, String> toString = element -> toParsableString.apply(auditLogFormatter, element);
     108             : 
     109         152 :     Stream<String> removedElements =
     110         152 :         Sets.difference(oldElements, newElements).stream()
     111         152 :             .map(toString)
     112         152 :             .map((removalFooterKey.getName() + ": ")::concat);
     113         152 :     Stream<String> addedElements =
     114         152 :         Sets.difference(newElements, oldElements).stream()
     115         152 :             .map(toString)
     116         152 :             .map((additionFooterKey.getName() + ": ")::concat);
     117         152 :     return Stream.concat(removedElements, addedElements);
     118             :   }
     119             : }

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