You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnsetAction.java 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 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.ws;
  21. import javax.annotation.Nullable;
  22. import org.sonar.api.server.ws.Request;
  23. import org.sonar.api.server.ws.Response;
  24. import org.sonar.api.server.ws.WebService;
  25. import org.sonar.api.web.UserRole;
  26. import org.sonar.core.documentation.DocumentationLinkGenerator;
  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.component.BranchDto;
  32. import org.sonar.db.newcodeperiod.NewCodePeriodDao;
  33. import org.sonar.db.project.ProjectDto;
  34. import org.sonar.server.component.ComponentFinder;
  35. import org.sonar.server.exceptions.NotFoundException;
  36. import org.sonar.server.common.newcodeperiod.CaycUtils;
  37. import org.sonar.server.user.UserSession;
  38. import static java.lang.String.format;
  39. import static org.sonar.server.ws.WsUtils.createHtmlExternalLink;
  40. public class UnsetAction implements NewCodePeriodsWsAction {
  41. private static final String BRANCH = "branch";
  42. private static final String PROJECT = "project";
  43. private static final String INSTANCE = "instance";
  44. private static final String NON_COMPLIANT_CAYC_ERROR_MESSAGE = "Failed to unset the New Code Definition. Your %s " +
  45. "New Code Definition is not compatible with the Clean as You Code methodology. Please update your %s New Code Definition";
  46. private final DbClient dbClient;
  47. private final UserSession userSession;
  48. private final ComponentFinder componentFinder;
  49. private final PlatformEditionProvider editionProvider;
  50. private final NewCodePeriodDao newCodePeriodDao;
  51. private final String newCodeDefinitionDocumentationUrl;
  52. public UnsetAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder,
  53. PlatformEditionProvider editionProvider, NewCodePeriodDao newCodePeriodDao, DocumentationLinkGenerator documentationLinkGenerator) {
  54. this.dbClient = dbClient;
  55. this.userSession = userSession;
  56. this.componentFinder = componentFinder;
  57. this.editionProvider = editionProvider;
  58. this.newCodePeriodDao = newCodePeriodDao;
  59. this.newCodeDefinitionDocumentationUrl = documentationLinkGenerator.getDocumentationLink("/project-administration/defining-new-code/");
  60. }
  61. @Override
  62. public void define(WebService.NewController context) {
  63. WebService.NewAction action = context.createAction("unset")
  64. .setPost(true)
  65. .setDescription("Unsets the " + createHtmlExternalLink(newCodeDefinitionDocumentationUrl, "new code definition") +
  66. " for a branch, project or global. It requires the inherited New Code Definition to be compatible with the Clean as You Code methodology, " +
  67. "and one of the following permissions: " +
  68. "<ul>" +
  69. "<li>'Administer System' to change the global setting</li>" +
  70. "<li>'Administer' rights for a specified component</li>" +
  71. "</ul>")
  72. .setSince("8.0")
  73. .setHandler(this);
  74. action.createParam(PROJECT)
  75. .setDescription("Project key");
  76. action.createParam(BRANCH)
  77. .setDescription("Branch key");
  78. }
  79. @Override
  80. public void handle(Request request, Response response) throws Exception {
  81. String projectKey = request.getParam(PROJECT).emptyAsNull().or(() -> null);
  82. String branchKey = request.getParam(BRANCH).emptyAsNull().or(() -> null);
  83. if (projectKey == null && branchKey != null) {
  84. throw new IllegalArgumentException("If branch key is specified, project key needs to be specified too");
  85. }
  86. try (DbSession dbSession = dbClient.openSession(false)) {
  87. String projectUuid = null;
  88. String branchUuid = null;
  89. // in CE set main branch value instead of project value
  90. boolean isCommunityEdition = editionProvider.get().filter(t -> t == EditionProvider.Edition.COMMUNITY).isPresent();
  91. if (projectKey != null) {
  92. ProjectDto project = getProject(dbSession, projectKey);
  93. userSession.checkEntityPermission(UserRole.ADMIN, project);
  94. projectUuid = project.getUuid();
  95. if (branchKey != null) {
  96. branchUuid = getBranch(dbSession, project, branchKey).getUuid();
  97. } else if (isCommunityEdition) {
  98. branchUuid = getMainBranch(dbSession, project).getUuid();
  99. }
  100. checkInheritedNcdCompliant(dbSession, projectUuid, branchUuid);
  101. } else {
  102. userSession.checkIsSystemAdministrator();
  103. }
  104. newCodePeriodDao.delete(dbSession, projectUuid, branchUuid);
  105. if (isCommunityEdition && projectUuid != null) {
  106. // also delete project default in case it was somehow set (downgrade from another edition, for example)
  107. newCodePeriodDao.delete(dbSession, projectUuid, null);
  108. }
  109. dbSession.commit();
  110. }
  111. }
  112. private void checkInheritedNcdCompliant(DbSession dbSession, String projectUuid, @Nullable String branchUuid) {
  113. if (branchUuid != null) {
  114. if (dbClient.newCodePeriodDao().selectByBranch(dbSession, projectUuid, branchUuid).isPresent()) {
  115. checkBranchInheritedNcdCompliant(dbSession, projectUuid);
  116. }
  117. } else if (dbClient.newCodePeriodDao().selectByProject(dbSession, projectUuid).isPresent()) {
  118. checkInstanceNcdCompliant(dbSession);
  119. }
  120. }
  121. private BranchDto getMainBranch(DbSession dbSession, ProjectDto project) {
  122. return dbClient.branchDao().selectByProject(dbSession, project)
  123. .stream().filter(BranchDto::isMain)
  124. .findFirst()
  125. .orElseThrow(() -> new NotFoundException(format("Main branch in project '%s' not found", project.getKey())));
  126. }
  127. private BranchDto getBranch(DbSession dbSession, ProjectDto project, String branchKey) {
  128. return dbClient.branchDao().selectByBranchKey(dbSession, project.getUuid(), branchKey)
  129. .orElseThrow(() -> new NotFoundException(format("Branch '%s' in project '%s' not found", branchKey, project.getKey())));
  130. }
  131. private ProjectDto getProject(DbSession dbSession, String projectKey) {
  132. return componentFinder.getProjectByKey(dbSession, projectKey);
  133. }
  134. private void checkInstanceNcdCompliant(DbSession dbSession) {
  135. var instanceNcd = newCodePeriodDao.selectGlobal(dbSession);
  136. if (instanceNcd.isPresent()) {
  137. var ncd = instanceNcd.get();
  138. if (!CaycUtils.isNewCodePeriodCompliant(ncd.getType(), ncd.getValue())) {
  139. throw new IllegalArgumentException(format(NON_COMPLIANT_CAYC_ERROR_MESSAGE, INSTANCE, INSTANCE));
  140. }
  141. }
  142. }
  143. private void checkBranchInheritedNcdCompliant(DbSession dbSession, String projectUuid) {
  144. var projectNcd = newCodePeriodDao.selectByProject(dbSession, projectUuid);
  145. if (projectNcd.isPresent()) {
  146. var ncd = projectNcd.get();
  147. if (!CaycUtils.isNewCodePeriodCompliant(ncd.getType(), ncd.getValue())) {
  148. throw new IllegalArgumentException(format(NON_COMPLIANT_CAYC_ERROR_MESSAGE, PROJECT, PROJECT));
  149. }
  150. } else {
  151. checkInstanceNcdCompliant(dbSession);
  152. }
  153. }
  154. }