LCOV - code coverage report
Current view: top level - server/restapi/project - CreateLabel.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 70 73 95.9 %
Date: 2022-11-19 15:00:39 Functions: 3 3 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2019 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.project;
      16             : 
      17             : import com.google.common.base.Strings;
      18             : import com.google.gerrit.entities.LabelFunction;
      19             : import com.google.gerrit.entities.LabelType;
      20             : import com.google.gerrit.entities.LabelValue;
      21             : import com.google.gerrit.extensions.common.LabelDefinitionInfo;
      22             : import com.google.gerrit.extensions.common.LabelDefinitionInput;
      23             : import com.google.gerrit.extensions.restapi.AuthException;
      24             : import com.google.gerrit.extensions.restapi.BadRequestException;
      25             : import com.google.gerrit.extensions.restapi.IdString;
      26             : import com.google.gerrit.extensions.restapi.ResourceConflictException;
      27             : import com.google.gerrit.extensions.restapi.Response;
      28             : import com.google.gerrit.extensions.restapi.RestCollectionCreateView;
      29             : import com.google.gerrit.index.query.QueryParseException;
      30             : import com.google.gerrit.server.CurrentUser;
      31             : import com.google.gerrit.server.git.meta.MetaDataUpdate;
      32             : import com.google.gerrit.server.permissions.PermissionBackend;
      33             : import com.google.gerrit.server.permissions.PermissionBackendException;
      34             : import com.google.gerrit.server.permissions.ProjectPermission;
      35             : import com.google.gerrit.server.project.LabelDefinitionJson;
      36             : import com.google.gerrit.server.project.LabelResource;
      37             : import com.google.gerrit.server.project.ProjectCache;
      38             : import com.google.gerrit.server.project.ProjectConfig;
      39             : import com.google.gerrit.server.project.ProjectResource;
      40             : import com.google.gerrit.server.query.approval.ApprovalQueryBuilder;
      41             : import com.google.inject.Inject;
      42             : import com.google.inject.Provider;
      43             : import com.google.inject.Singleton;
      44             : import java.io.IOException;
      45             : import java.util.List;
      46             : import java.util.Optional;
      47             : import org.eclipse.jgit.errors.ConfigInvalidException;
      48             : 
      49             : @Singleton
      50             : public class CreateLabel
      51             :     implements RestCollectionCreateView<ProjectResource, LabelResource, LabelDefinitionInput> {
      52             :   private final Provider<CurrentUser> user;
      53             :   private final PermissionBackend permissionBackend;
      54             :   private final MetaDataUpdate.User updateFactory;
      55             :   private final ProjectConfig.Factory projectConfigFactory;
      56             :   private final ProjectCache projectCache;
      57             :   private final ApprovalQueryBuilder approvalQueryBuilder;
      58             : 
      59             :   @Inject
      60             :   public CreateLabel(
      61             :       Provider<CurrentUser> user,
      62             :       PermissionBackend permissionBackend,
      63             :       MetaDataUpdate.User updateFactory,
      64             :       ProjectConfig.Factory projectConfigFactory,
      65             :       ProjectCache projectCache,
      66         146 :       ApprovalQueryBuilder approvalQueryBuilder) {
      67         146 :     this.user = user;
      68         146 :     this.permissionBackend = permissionBackend;
      69         146 :     this.updateFactory = updateFactory;
      70         146 :     this.projectConfigFactory = projectConfigFactory;
      71         146 :     this.projectCache = projectCache;
      72         146 :     this.approvalQueryBuilder = approvalQueryBuilder;
      73         146 :   }
      74             : 
      75             :   @Override
      76             :   public Response<LabelDefinitionInfo> apply(
      77             :       ProjectResource rsrc, IdString id, LabelDefinitionInput input)
      78             :       throws AuthException, BadRequestException, ResourceConflictException,
      79             :           PermissionBackendException, IOException, ConfigInvalidException {
      80           4 :     if (!user.get().isIdentifiedUser()) {
      81           1 :       throw new AuthException("Authentication required");
      82             :     }
      83             : 
      84           4 :     permissionBackend
      85           4 :         .currentUser()
      86           4 :         .project(rsrc.getNameKey())
      87           4 :         .check(ProjectPermission.WRITE_CONFIG);
      88             : 
      89           4 :     if (input == null) {
      90           0 :       input = new LabelDefinitionInput();
      91             :     }
      92             : 
      93           4 :     if (input.name != null && !input.name.equals(id.get())) {
      94           1 :       throw new BadRequestException("name in input must match name in URL");
      95             :     }
      96             : 
      97           4 :     try (MetaDataUpdate md = updateFactory.create(rsrc.getNameKey())) {
      98           4 :       ProjectConfig config = projectConfigFactory.read(md);
      99             : 
     100           3 :       LabelType labelType = createLabel(config, id.get(), input);
     101             : 
     102           3 :       if (input.commitMessage != null) {
     103           1 :         md.setMessage(Strings.emptyToNull(input.commitMessage.trim()));
     104             :       } else {
     105           3 :         md.setMessage("Update label");
     106             :       }
     107             : 
     108           3 :       config.commit(md);
     109             : 
     110           3 :       projectCache.evictAndReindex(rsrc.getProjectState().getProject());
     111             : 
     112           3 :       return Response.created(LabelDefinitionJson.format(rsrc.getNameKey(), labelType));
     113             :     }
     114             :   }
     115             : 
     116             :   /**
     117             :    * Creates a new label.
     118             :    *
     119             :    * @param config the project config
     120             :    * @param label the name of the new label
     121             :    * @param input the input that describes the new label
     122             :    * @return the created label type
     123             :    * @throws BadRequestException if there was invalid data in the input
     124             :    * @throws ResourceConflictException if the label cannot be created due to a conflict
     125             :    */
     126             :   public LabelType createLabel(ProjectConfig config, String label, LabelDefinitionInput input)
     127             :       throws BadRequestException, ResourceConflictException {
     128           5 :     if (config.getLabelSections().containsKey(label)) {
     129           2 :       throw new ResourceConflictException(String.format("label %s already exists", label));
     130             :     }
     131             : 
     132           5 :     for (String labelName : config.getLabelSections().keySet()) {
     133           3 :       if (labelName.equalsIgnoreCase(label)) {
     134           2 :         throw new ResourceConflictException(
     135           2 :             String.format("label %s conflicts with existing label %s", label, labelName));
     136             :       }
     137           3 :     }
     138             : 
     139           5 :     if (input.values == null || input.values.isEmpty()) {
     140           3 :       throw new BadRequestException("values are required");
     141             :     }
     142             : 
     143             :     try {
     144           4 :       LabelType.checkName(label);
     145           1 :     } catch (IllegalArgumentException e) {
     146           1 :       throw new BadRequestException("invalid name: " + label, e);
     147           4 :     }
     148             : 
     149           4 :     List<LabelValue> values = LabelDefinitionInputParser.parseValues(input.values);
     150           4 :     LabelType.Builder labelType = LabelType.builder(LabelType.checkName(label), values);
     151             : 
     152           4 :     if (input.description != null) {
     153           1 :       String description = Strings.emptyToNull(input.description.trim());
     154           1 :       labelType.setDescription(Optional.ofNullable(description));
     155             :     }
     156             : 
     157           4 :     if (input.function != null && !input.function.trim().isEmpty()) {
     158           4 :       labelType.setFunction(LabelDefinitionInputParser.parseFunction(input.function));
     159             :     } else {
     160           2 :       labelType.setFunction(LabelFunction.MAX_WITH_BLOCK);
     161             :     }
     162             : 
     163           4 :     if (input.defaultValue != null) {
     164           1 :       labelType.setDefaultValue(
     165           1 :           LabelDefinitionInputParser.parseDefaultValue(labelType, input.defaultValue));
     166             :     }
     167             : 
     168           4 :     if (input.branches != null) {
     169           1 :       labelType.setRefPatterns(LabelDefinitionInputParser.parseBranches(input.branches));
     170             :     }
     171             : 
     172           4 :     if (input.canOverride != null) {
     173           1 :       labelType.setCanOverride(input.canOverride);
     174             :     }
     175             : 
     176           4 :     if (input.copyCondition != null) {
     177             :       try {
     178           1 :         approvalQueryBuilder.parse(input.copyCondition);
     179           1 :       } catch (QueryParseException e) {
     180           1 :         throw new BadRequestException(
     181           1 :             "unable to parse copy condition. got: " + input.copyCondition + ". " + e.getMessage(),
     182             :             e);
     183           1 :       }
     184           1 :       if (Boolean.TRUE.equals(input.unsetCopyCondition)) {
     185           0 :         throw new BadRequestException("can't set and unset copyCondition in the same request");
     186             :       }
     187           1 :       labelType.setCopyCondition(Strings.emptyToNull(input.copyCondition));
     188             :     }
     189           4 :     if (Boolean.TRUE.equals(input.unsetCopyCondition)) {
     190           0 :       labelType.setCopyCondition(null);
     191             :     }
     192             : 
     193           4 :     if (input.allowPostSubmit != null) {
     194           1 :       labelType.setAllowPostSubmit(input.allowPostSubmit);
     195             :     }
     196             : 
     197           4 :     if (input.ignoreSelfApproval != null) {
     198           2 :       labelType.setIgnoreSelfApproval(input.ignoreSelfApproval);
     199             :     }
     200             : 
     201           4 :     LabelType lt = labelType.build();
     202           4 :     config.upsertLabelType(lt);
     203             : 
     204           4 :     return lt;
     205             :   }
     206             : }

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