您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ComponentUpdater.java 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 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.component;
  21. import com.google.common.collect.ImmutableSet;
  22. import java.util.Date;
  23. import java.util.Locale;
  24. import java.util.Optional;
  25. import java.util.Set;
  26. import java.util.function.Consumer;
  27. import javax.annotation.Nullable;
  28. import org.sonar.api.resources.Qualifiers;
  29. import org.sonar.api.resources.Scopes;
  30. import org.sonar.api.utils.System2;
  31. import org.sonar.core.i18n.I18n;
  32. import org.sonar.core.util.UuidFactory;
  33. import org.sonar.db.DbClient;
  34. import org.sonar.db.DbSession;
  35. import org.sonar.db.component.BranchDto;
  36. import org.sonar.db.component.BranchType;
  37. import org.sonar.db.component.ComponentDto;
  38. import org.sonar.db.project.ProjectDto;
  39. import org.sonar.server.es.ProjectIndexer.Cause;
  40. import org.sonar.server.es.ProjectIndexers;
  41. import org.sonar.server.favorite.FavoriteUpdater;
  42. import org.sonar.server.permission.PermissionTemplateService;
  43. import static java.util.Collections.singletonList;
  44. import static org.sonar.api.resources.Qualifiers.PROJECT;
  45. import static org.sonar.core.component.ComponentKeys.ALLOWED_CHARACTERS_MESSAGE;
  46. import static org.sonar.core.component.ComponentKeys.isValidProjectKey;
  47. import static org.sonar.server.exceptions.BadRequestException.checkRequest;
  48. public class ComponentUpdater {
  49. private static final Set<String> MAIN_BRANCH_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.APP);
  50. private final DbClient dbClient;
  51. private final I18n i18n;
  52. private final System2 system2;
  53. private final PermissionTemplateService permissionTemplateService;
  54. private final FavoriteUpdater favoriteUpdater;
  55. private final ProjectIndexers projectIndexers;
  56. private final UuidFactory uuidFactory;
  57. public ComponentUpdater(DbClient dbClient, I18n i18n, System2 system2,
  58. PermissionTemplateService permissionTemplateService, FavoriteUpdater favoriteUpdater,
  59. ProjectIndexers projectIndexers, UuidFactory uuidFactory) {
  60. this.dbClient = dbClient;
  61. this.i18n = i18n;
  62. this.system2 = system2;
  63. this.permissionTemplateService = permissionTemplateService;
  64. this.favoriteUpdater = favoriteUpdater;
  65. this.projectIndexers = projectIndexers;
  66. this.uuidFactory = uuidFactory;
  67. }
  68. /**
  69. * - Create component
  70. * - Apply default permission template
  71. * - Add component to favorite if the component has the 'Project Creators' permission
  72. * - Index component in es indexes
  73. */
  74. public ComponentDto create(DbSession dbSession, NewComponent newComponent, @Nullable String userUuid, @Nullable String userLogin) {
  75. ComponentDto componentDto = createWithoutCommit(dbSession, newComponent, userUuid, userLogin, c -> {
  76. });
  77. commitAndIndex(dbSession, componentDto);
  78. return componentDto;
  79. }
  80. /**
  81. * Create component without committing.
  82. * Don't forget to call commitAndIndex(...) when ready to commit.
  83. */
  84. public ComponentDto createWithoutCommit(DbSession dbSession, NewComponent newComponent,
  85. @Nullable String userUuid, @Nullable String userLogin, Consumer<ComponentDto> componentModifier) {
  86. return createWithoutCommit(dbSession, newComponent, userUuid, userLogin, null, componentModifier);
  87. }
  88. /**
  89. * Create component without committing.
  90. * Don't forget to call commitAndIndex(...) when ready to commit.
  91. */
  92. public ComponentDto createWithoutCommit(DbSession dbSession, NewComponent newComponent,
  93. @Nullable String userUuid, @Nullable String userLogin, @Nullable String mainBranchName,
  94. Consumer<ComponentDto> componentModifier) {
  95. checkKeyFormat(newComponent.qualifier(), newComponent.key());
  96. ComponentDto componentDto = createRootComponent(dbSession, newComponent, componentModifier);
  97. if (isRootProject(componentDto)) {
  98. createMainBranch(dbSession, componentDto.uuid(), mainBranchName);
  99. }
  100. handlePermissionTemplate(dbSession, componentDto, userUuid, userLogin);
  101. return componentDto;
  102. }
  103. public void commitAndIndex(DbSession dbSession, ComponentDto componentDto) {
  104. projectIndexers.commitAndIndexComponents(dbSession, singletonList(componentDto), Cause.PROJECT_CREATION);
  105. }
  106. private ComponentDto createRootComponent(DbSession session, NewComponent newComponent, Consumer<ComponentDto> componentModifier) {
  107. checkRequest(!dbClient.componentDao().selectByKey(session, newComponent.key()).isPresent(),
  108. "Could not create %s, key already exists: %s", getQualifierToDisplay(newComponent.qualifier()), newComponent.key());
  109. long now = system2.now();
  110. String uuid = uuidFactory.create();
  111. ComponentDto component = new ComponentDto()
  112. .setUuid(uuid)
  113. .setUuidPath(ComponentDto.UUID_PATH_OF_ROOT)
  114. .setRootUuid(uuid)
  115. .setModuleUuid(null)
  116. .setModuleUuidPath(ComponentDto.UUID_PATH_SEPARATOR + uuid + ComponentDto.UUID_PATH_SEPARATOR)
  117. .setProjectUuid(uuid)
  118. .setDbKey(newComponent.key())
  119. .setName(newComponent.name())
  120. .setDescription(newComponent.description())
  121. .setLongName(newComponent.name())
  122. .setScope(Scopes.PROJECT)
  123. .setQualifier(newComponent.qualifier())
  124. .setPrivate(newComponent.isPrivate())
  125. .setCreatedAt(new Date(now));
  126. componentModifier.accept(component);
  127. dbClient.componentDao().insert(session, component);
  128. if (isRootProject(component)) {
  129. ProjectDto projectDto = toProjectDto(component, now);
  130. dbClient.projectDao().insert(session, projectDto);
  131. }
  132. return component;
  133. }
  134. private static ProjectDto toProjectDto(ComponentDto component, long now) {
  135. return new ProjectDto()
  136. .setUuid(component.uuid())
  137. .setKey(component.getKey())
  138. .setQualifier(component.qualifier())
  139. .setName(component.name())
  140. .setPrivate(component.isPrivate())
  141. .setDescription(component.description())
  142. .setUpdatedAt(now)
  143. .setCreatedAt(now);
  144. }
  145. private static boolean isRootProject(ComponentDto componentDto) {
  146. return Scopes.PROJECT.equals(componentDto.scope())
  147. && MAIN_BRANCH_QUALIFIERS.contains(componentDto.qualifier());
  148. }
  149. private void createMainBranch(DbSession session, String componentUuid, @Nullable String mainBranch) {
  150. BranchDto branch = new BranchDto()
  151. .setBranchType(BranchType.BRANCH)
  152. .setUuid(componentUuid)
  153. .setKey(Optional.ofNullable(mainBranch).orElse(BranchDto.DEFAULT_MAIN_BRANCH_NAME))
  154. .setMergeBranchUuid(null)
  155. .setExcludeFromPurge(true)
  156. .setProjectUuid(componentUuid);
  157. dbClient.branchDao().upsert(session, branch);
  158. }
  159. private void handlePermissionTemplate(DbSession dbSession, ComponentDto componentDto, @Nullable String userUuid, @Nullable String userLogin) {
  160. permissionTemplateService.applyDefaultToNewComponent(dbSession, componentDto, userUuid);
  161. if (componentDto.qualifier().equals(PROJECT)
  162. && permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(dbSession, componentDto)) {
  163. favoriteUpdater.add(dbSession, componentDto, userUuid, userLogin, false);
  164. }
  165. }
  166. private void checkKeyFormat(String qualifier, String key) {
  167. checkRequest(isValidProjectKey(key), "Malformed key for %s: '%s'. %s.", getQualifierToDisplay(qualifier), key, ALLOWED_CHARACTERS_MESSAGE);
  168. }
  169. private String getQualifierToDisplay(String qualifier) {
  170. return i18n.message(Locale.getDefault(), "qualifier." + qualifier, "Project");
  171. }
  172. }