3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.server.newcodeperiod;
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 import org.sonar.server.component.ComponentCreationData;
36 import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
37 import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
38 import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
40 public class NewCodeDefinitionResolver {
41 private static final String BEGIN_LIST = "<ul>";
43 private static final String END_LIST = "</ul>";
44 private static final String BEGIN_ITEM_LIST = "<li>";
45 private static final String END_ITEM_LIST = "</li>";
47 public static final String NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION = "Project New Code Definition Type<br/>" +
48 "New code definitions of the following types are allowed:" +
50 BEGIN_ITEM_LIST + PREVIOUS_VERSION.name() + END_ITEM_LIST +
51 BEGIN_ITEM_LIST + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
52 BEGIN_ITEM_LIST + REFERENCE_BRANCH.name() + " - will default to the main branch." + END_ITEM_LIST +
55 public static final String NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION = "Project New Code Definition Value<br/>" +
56 "For each new code definition type, a different value is expected:" +
58 BEGIN_ITEM_LIST + "no value, when the new code definition type is " + PREVIOUS_VERSION.name() + " and " + REFERENCE_BRANCH.name() + END_ITEM_LIST +
59 BEGIN_ITEM_LIST + "a number between 1 and 90, when the new code definition type is " + NUMBER_OF_DAYS.name() + END_ITEM_LIST +
62 private static final String UNEXPECTED_VALUE_ERROR_MESSAGE = "Unexpected value for newCodeDefinitionType '%s'";
64 private static final EnumSet<NewCodePeriodType> projectCreationNCDTypes = EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, REFERENCE_BRANCH);
66 private final DbClient dbClient;
67 private final PlatformEditionProvider editionProvider;
69 public NewCodeDefinitionResolver(DbClient dbClient, PlatformEditionProvider editionProvider) {
70 this.dbClient = dbClient;
71 this.editionProvider = editionProvider;
74 public void createNewCodeDefinition(DbSession dbSession, String projectUuid, String mainBranchUuid,
75 String defaultBranchName, String newCodeDefinitionType, String newCodeDefinitionValue) {
77 boolean isCommunityEdition = editionProvider.get().filter(EditionProvider.Edition.COMMUNITY::equals).isPresent();
78 NewCodePeriodType newCodePeriodType = parseNewCodeDefinitionType(newCodeDefinitionType);
80 NewCodePeriodDto dto = new NewCodePeriodDto();
81 dto.setType(newCodePeriodType);
82 dto.setProjectUuid(projectUuid);
84 if (isCommunityEdition) {
85 dto.setBranchUuid(mainBranchUuid);
88 getNewCodeDefinitionValueProjectCreation(newCodePeriodType, newCodeDefinitionValue, defaultBranchName).ifPresent(dto::setValue);
90 if (!CaycUtils.isNewCodePeriodCompliant(dto.getType(), dto.getValue())) {
91 throw new IllegalArgumentException("Failed to set the New Code Definition. The given value is not compatible with the Clean as You Code methodology. "
92 + "Please refer to the documentation for compliant options.");
95 dbClient.newCodePeriodDao().insert(dbSession, dto);
98 public static void checkNewCodeDefinitionParam(@Nullable String newCodeDefinitionType, @Nullable String newCodeDefinitionValue) {
99 if (newCodeDefinitionType == null && newCodeDefinitionValue != null) {
100 throw new IllegalArgumentException("New code definition type is required when new code definition value is provided");
104 private static Optional<String> getNewCodeDefinitionValueProjectCreation(NewCodePeriodType type, @Nullable String value, String defaultBranchName) {
105 return switch (type) {
106 case PREVIOUS_VERSION -> {
107 Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
108 yield Optional.empty();
110 case NUMBER_OF_DAYS -> {
111 requireValue(type, value);
112 yield Optional.of(parseDays(value));
114 case REFERENCE_BRANCH -> {
115 Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
116 yield Optional.of(defaultBranchName);
118 default -> throw new IllegalStateException("Unexpected type: " + type);
122 private static String parseDays(String value) {
124 return Integer.toString(NewCodePeriodParser.parseDays(value));
125 } catch (Exception e) {
126 throw new IllegalArgumentException("Failed to parse number of days: " + value);
130 private static void requireValue(NewCodePeriodType type, @Nullable String value) {
131 Preconditions.checkArgument(value != null, "New code definition type '%s' requires a newCodeDefinitionValue", type);
134 private static NewCodePeriodType parseNewCodeDefinitionType(String typeStr) {
135 NewCodePeriodType type;
137 type = NewCodePeriodType.valueOf(typeStr.toUpperCase(Locale.US));
138 } catch (IllegalArgumentException e) {
139 throw new IllegalArgumentException("Invalid type: " + typeStr);
145 private static void validateType(NewCodePeriodType type) {
146 Preconditions.checkArgument(projectCreationNCDTypes.contains(type), "Invalid type '%s'. `newCodeDefinitionType` can only be set with types: %s",
147 type, projectCreationNCDTypes);