]> source.dussan.org Git - sonarqube.git/blob
a91268891c2ee36bb2fdcbe9cea983d1dbb63fc5
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.newcodeperiod;
21
22 import com.google.common.base.Preconditions;
23 import java.util.EnumSet;
24 import java.util.Locale;
25 import java.util.Optional;
26 import javax.annotation.Nullable;
27 import org.sonar.core.platform.EditionProvider;
28 import org.sonar.core.platform.PlatformEditionProvider;
29 import org.sonar.db.DbClient;
30 import org.sonar.db.DbSession;
31 import org.sonar.db.newcodeperiod.NewCodePeriodDto;
32 import org.sonar.db.newcodeperiod.NewCodePeriodParser;
33 import org.sonar.db.newcodeperiod.NewCodePeriodType;
34
35 import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
36 import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
37 import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
38
39 public class NewCodeDefinitionResolver {
40   private static final String BEGIN_LIST = "<ul>";
41
42   private static final String END_LIST = "</ul>";
43   private static final String BEGIN_ITEM_LIST = "<li>";
44   private static final String END_ITEM_LIST = "</li>";
45
46   public static final String NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION = "Project New Code Definition Type<br/>" +
47     "New code definitions of the following types are allowed:" +
48     BEGIN_LIST +
49     BEGIN_ITEM_LIST + PREVIOUS_VERSION.name() + END_ITEM_LIST +
50     BEGIN_ITEM_LIST + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
51     BEGIN_ITEM_LIST + REFERENCE_BRANCH.name() + " - will default to the main branch." + END_ITEM_LIST +
52     END_LIST;
53
54   public static final String NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION = "Project New Code Definition Value<br/>" +
55     "For each new code definition type, a different value is expected:" +
56     BEGIN_LIST +
57     BEGIN_ITEM_LIST + "no value, when the new code definition type is " + PREVIOUS_VERSION.name() + " and " + REFERENCE_BRANCH.name() + END_ITEM_LIST +
58     BEGIN_ITEM_LIST + "a number between 1 and 90, when the new code definition type is " + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
59     END_LIST;
60
61   private static final String UNEXPECTED_VALUE_ERROR_MESSAGE = "Unexpected value for newCodeDefinitionType '%s'";
62
63   private static final EnumSet<NewCodePeriodType> projectCreationNCDTypes = EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, REFERENCE_BRANCH);
64
65   private final DbClient dbClient;
66   private final PlatformEditionProvider editionProvider;
67
68   public NewCodeDefinitionResolver(DbClient dbClient, PlatformEditionProvider editionProvider) {
69     this.dbClient = dbClient;
70     this.editionProvider = editionProvider;
71   }
72
73   public void createNewCodeDefinition(DbSession dbSession, String projectUuid, String mainBranchUuid,
74     String defaultBranchName, String newCodeDefinitionType, String newCodeDefinitionValue) {
75
76     boolean isCommunityEdition = editionProvider.get().filter(EditionProvider.Edition.COMMUNITY::equals).isPresent();
77     NewCodePeriodType newCodePeriodType = parseNewCodeDefinitionType(newCodeDefinitionType);
78
79     NewCodePeriodDto dto = new NewCodePeriodDto();
80     dto.setType(newCodePeriodType);
81     dto.setProjectUuid(projectUuid);
82
83     if (isCommunityEdition) {
84       dto.setBranchUuid(mainBranchUuid);
85     }
86
87     getNewCodeDefinitionValueProjectCreation(newCodePeriodType, newCodeDefinitionValue, defaultBranchName).ifPresent(dto::setValue);
88
89     if (!CaycUtils.isNewCodePeriodCompliant(dto.getType(), dto.getValue())) {
90       throw new IllegalArgumentException("Failed to set the New Code Definition. The given value is not compatible with the Clean as You Code methodology. "
91         + "Please refer to the documentation for compliant options.");
92     }
93
94     dbClient.newCodePeriodDao().insert(dbSession, dto);
95   }
96
97   public static void checkNewCodeDefinitionParam(@Nullable String newCodeDefinitionType, @Nullable String newCodeDefinitionValue) {
98     if (newCodeDefinitionType == null && newCodeDefinitionValue != null) {
99       throw new IllegalArgumentException("New code definition type is required when new code definition value is provided");
100     }
101   }
102
103   private static Optional<String> getNewCodeDefinitionValueProjectCreation(NewCodePeriodType type, @Nullable String value, String defaultBranchName) {
104     return switch (type) {
105       case PREVIOUS_VERSION -> {
106         Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
107         yield Optional.empty();
108       }
109       case NUMBER_OF_DAYS -> {
110         requireValue(type, value);
111         yield Optional.of(parseDays(value));
112       }
113       case REFERENCE_BRANCH -> {
114         Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
115         yield Optional.of(defaultBranchName);
116       }
117       default -> throw new IllegalStateException("Unexpected type: " + type);
118     };
119   }
120
121   private static String parseDays(String value) {
122     try {
123       return Integer.toString(NewCodePeriodParser.parseDays(value));
124     } catch (Exception e) {
125       throw new IllegalArgumentException("Failed to parse number of days: " + value);
126     }
127   }
128
129   private static void requireValue(NewCodePeriodType type, @Nullable String value) {
130     Preconditions.checkArgument(value != null, "New code definition type '%s' requires a newCodeDefinitionValue", type);
131   }
132
133   private static NewCodePeriodType parseNewCodeDefinitionType(String typeStr) {
134     NewCodePeriodType type;
135     try {
136       type = NewCodePeriodType.valueOf(typeStr.toUpperCase(Locale.US));
137     } catch (IllegalArgumentException e) {
138       throw new IllegalArgumentException("Invalid type: " + typeStr);
139     }
140     validateType(type);
141     return type;
142   }
143
144   private static void validateType(NewCodePeriodType type) {
145     Preconditions.checkArgument(projectCreationNCDTypes.contains(type), "Invalid type '%s'. `newCodeDefinitionType` can only be set with types: %s",
146       type, projectCreationNCDTypes);
147   }
148
149 }