]> source.dussan.org Git - sonarqube.git/blob
64085be3fd29b913f4e30f4cccc1f7ab6ba2c29d
[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 import org.sonar.server.component.ComponentCreationData;
35
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;
39
40 public class NewCodeDefinitionResolver {
41   private static final String BEGIN_LIST = "<ul>";
42
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>";
46
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:" +
49     BEGIN_LIST +
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 +
53     END_LIST;
54
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:" +
57     BEGIN_LIST +
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 +
60     END_LIST;
61
62   private static final String UNEXPECTED_VALUE_ERROR_MESSAGE = "Unexpected value for newCodeDefinitionType '%s'";
63
64   private static final EnumSet<NewCodePeriodType> projectCreationNCDTypes = EnumSet.of(PREVIOUS_VERSION, NUMBER_OF_DAYS, REFERENCE_BRANCH);
65
66   private final DbClient dbClient;
67   private final PlatformEditionProvider editionProvider;
68
69   public NewCodeDefinitionResolver(DbClient dbClient, PlatformEditionProvider editionProvider) {
70     this.dbClient = dbClient;
71     this.editionProvider = editionProvider;
72   }
73
74   public void createNewCodeDefinition(DbSession dbSession, String projectUuid, String mainBranchUuid,
75     String defaultBranchName, String newCodeDefinitionType, String newCodeDefinitionValue) {
76
77     boolean isCommunityEdition = editionProvider.get().filter(EditionProvider.Edition.COMMUNITY::equals).isPresent();
78     NewCodePeriodType newCodePeriodType = parseNewCodeDefinitionType(newCodeDefinitionType);
79
80     NewCodePeriodDto dto = new NewCodePeriodDto();
81     dto.setType(newCodePeriodType);
82     dto.setProjectUuid(projectUuid);
83
84     if (isCommunityEdition) {
85       dto.setBranchUuid(mainBranchUuid);
86     }
87
88     getNewCodeDefinitionValueProjectCreation(newCodePeriodType, newCodeDefinitionValue, defaultBranchName).ifPresent(dto::setValue);
89
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.");
93     }
94
95     dbClient.newCodePeriodDao().insert(dbSession, dto);
96   }
97
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");
101     }
102   }
103
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();
109       }
110       case NUMBER_OF_DAYS -> {
111         requireValue(type, value);
112         yield Optional.of(parseDays(value));
113       }
114       case REFERENCE_BRANCH -> {
115         Preconditions.checkArgument(value == null, UNEXPECTED_VALUE_ERROR_MESSAGE, type);
116         yield Optional.of(defaultBranchName);
117       }
118       default -> throw new IllegalStateException("Unexpected type: " + type);
119     };
120   }
121
122   private static String parseDays(String value) {
123     try {
124       return Integer.toString(NewCodePeriodParser.parseDays(value));
125     } catch (Exception e) {
126       throw new IllegalArgumentException("Failed to parse number of days: " + value);
127     }
128   }
129
130   private static void requireValue(NewCodePeriodType type, @Nullable String value) {
131     Preconditions.checkArgument(value != null, "New code definition type '%s' requires a newCodeDefinitionValue", type);
132   }
133
134   private static NewCodePeriodType parseNewCodeDefinitionType(String typeStr) {
135     NewCodePeriodType type;
136     try {
137       type = NewCodePeriodType.valueOf(typeStr.toUpperCase(Locale.US));
138     } catch (IllegalArgumentException e) {
139       throw new IllegalArgumentException("Invalid type: " + typeStr);
140     }
141     validateType(type);
142     return type;
143   }
144
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);
148   }
149
150 }