@@ -70,7 +70,7 @@ public class ProjectAlmSettingDto { | |||
private long updatedAt; | |||
private long createdAt; | |||
String getUuid() { | |||
public String getUuid() { | |||
return uuid; | |||
} | |||
@@ -0,0 +1,38 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.common.project; | |||
import javax.annotation.Nullable; | |||
public record ImportProjectRequest( | |||
@Nullable | |||
String projectKey, | |||
@Nullable | |||
String projectName, | |||
String almSettingId, | |||
String repositoryIdentifier, | |||
@Nullable | |||
String newCodeDefinitionType, | |||
@Nullable | |||
String newCodeDefinitionValue, | |||
Boolean monorepo) { | |||
} |
@@ -0,0 +1,95 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.common.project; | |||
import java.util.Optional; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.alm.setting.AlmSettingDto; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.project.CreationMethod; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.common.almsettings.DevOpsProjectCreator; | |||
import org.sonar.server.common.almsettings.DevOpsProjectCreatorFactory; | |||
import org.sonar.server.common.almsettings.DevOpsProjectDescriptor; | |||
import org.sonar.server.common.component.ComponentUpdater; | |||
import org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver; | |||
import org.sonar.server.component.ComponentCreationData; | |||
import org.sonar.server.user.UserSession; | |||
import static java.lang.String.format; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.db.project.CreationMethod.getCreationMethod; | |||
import static org.sonar.db.project.CreationMethod.Category.ALM_IMPORT; | |||
import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.checkNewCodeDefinitionParam; | |||
@ServerSide | |||
public class ImportProjectService { | |||
private final DbClient dbClient; | |||
private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactory; | |||
private final UserSession userSession; | |||
private final ComponentUpdater componentUpdater; | |||
private final NewCodeDefinitionResolver newCodeDefinitionResolver; | |||
public ImportProjectService(DbClient dbClient, DevOpsProjectCreatorFactory devOpsProjectCreatorFactory, UserSession userSession, ComponentUpdater componentUpdater, | |||
NewCodeDefinitionResolver newCodeDefinitionResolver) { | |||
this.dbClient = dbClient; | |||
this.devOpsProjectCreatorFactory = devOpsProjectCreatorFactory; | |||
this.userSession = userSession; | |||
this.componentUpdater = componentUpdater; | |||
this.newCodeDefinitionResolver = newCodeDefinitionResolver; | |||
} | |||
public ImportedProject importProject(ImportProjectRequest request) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
checkNewCodeDefinitionParam(request.newCodeDefinitionType(), request.newCodeDefinitionValue()); | |||
AlmSettingDto almSetting = dbClient.almSettingDao().selectByUuid(dbSession, request.almSettingId()).orElseThrow(() -> new IllegalArgumentException("ALM setting not found")); | |||
String almUrl = requireNonNull(almSetting.getUrl()); | |||
DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(almSetting.getAlm(), almUrl, request.repositoryIdentifier()); | |||
DevOpsProjectCreator projectCreator = devOpsProjectCreatorFactory.getDevOpsProjectCreator(almSetting, projectDescriptor) | |||
.orElseThrow(() -> new IllegalArgumentException(format("Platform %s not supported", almSetting.getAlm().name()))); | |||
CreationMethod creationMethod = getCreationMethod(ALM_IMPORT, userSession.isAuthenticatedBrowserSession()); | |||
ComponentCreationData componentCreationData = projectCreator.createProjectAndBindToDevOpsPlatform( | |||
dbSession, | |||
creationMethod, | |||
request.monorepo(), | |||
request.projectKey(), | |||
request.projectName()); | |||
ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow(); | |||
BranchDto mainBranchDto = Optional.ofNullable(componentCreationData.mainBranchDto()).orElseThrow(); | |||
if (request.newCodeDefinitionType() != null) { | |||
newCodeDefinitionResolver.createNewCodeDefinition(dbSession, projectDto.getUuid(), mainBranchDto.getUuid(), | |||
mainBranchDto.getKey(), request.newCodeDefinitionType(), request.newCodeDefinitionValue()); | |||
} | |||
componentUpdater.commitAndIndex(dbSession, componentCreationData); | |||
ProjectAlmSettingDto projectAlmSettingDto = dbClient.projectAlmSettingDao().selectByProject(dbSession, projectDto) | |||
.orElseThrow(() -> new IllegalStateException("Project ALM setting was not created")); | |||
dbSession.commit(); | |||
return new ImportedProject(projectDto, projectAlmSettingDto); | |||
} | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.common.project; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.project.ProjectDto; | |||
public record ImportedProject(ProjectDto projectDto, ProjectAlmSettingDto projectAlmSettingDto){ | |||
} |
@@ -0,0 +1,212 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.common.project; | |||
import java.util.Optional; | |||
import org.junit.Rule; | |||
import org.junit.jupiter.api.Test; | |||
import org.mockito.Answers; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.alm.setting.ALM; | |||
import org.sonar.db.alm.setting.AlmSettingDto; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.common.almsettings.DevOpsProjectCreator; | |||
import org.sonar.server.common.almsettings.DevOpsProjectCreatorFactory; | |||
import org.sonar.server.common.almsettings.DevOpsProjectDescriptor; | |||
import org.sonar.server.common.component.ComponentUpdater; | |||
import org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver; | |||
import org.sonar.server.component.ComponentCreationData; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.lenient; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; | |||
class ImportProjectServiceTest { | |||
private static final String API_URL = "https://api.com"; | |||
private static final String PROJECT_UUID = "project-uuid"; | |||
private static final String REPOSITORY_ID = "repository-id"; | |||
private static final String PROJECT_KEY = "project-key"; | |||
private static final String PROJECT_NAME = "project-name"; | |||
private static final String MAIN_BRANCH_UUID = "main-branch-uuid"; | |||
private static final String MAIN_BRANCH_KEY = "main-branch-key"; | |||
private static final String ALM_SETTING_ID = "alm-setting-id"; | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactory = mock(); | |||
private final DbClient dbClient = mock(Answers.RETURNS_DEEP_STUBS); | |||
private final NewCodeDefinitionResolver newCodeDefinitionResolver = mock(); | |||
private final ComponentUpdater componentUpdater = mock(); | |||
private final ImportProjectService importProjectService = new ImportProjectService(dbClient, devOpsProjectCreatorFactory, userSession, componentUpdater, | |||
newCodeDefinitionResolver);; | |||
@Test | |||
void createdImportedProject_whenAlmSettingDoesntExist_throws() { | |||
userSession.logIn().addPermission(PROVISION_PROJECTS); | |||
DbSession dbSession = mockDbSession(); | |||
when(dbClient.almSettingDao().selectByUuid(dbSession, ALM_SETTING_ID)).thenReturn(Optional.empty()); | |||
ImportProjectRequest request = new ImportProjectRequest(PROJECT_KEY, PROJECT_NAME, ALM_SETTING_ID, REPOSITORY_ID, null, null, true); | |||
assertThatThrownBy(() -> importProjectService.importProject(request)) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("ALM setting not found"); | |||
} | |||
@Test | |||
void createImportedProject_whenAlmIsNotSupported_throws() { | |||
userSession.logIn().addPermission(PROVISION_PROJECTS); | |||
DbSession dbSession = mockDbSession(); | |||
AlmSettingDto almSetting = mockAlmSetting(dbSession); | |||
when(devOpsProjectCreatorFactory.getDevOpsProjectCreator(eq(almSetting), any())) | |||
.thenReturn(Optional.empty()); | |||
ImportProjectRequest request = new ImportProjectRequest(PROJECT_KEY, PROJECT_NAME, ALM_SETTING_ID, REPOSITORY_ID, null, null, true); | |||
assertThatThrownBy(() -> importProjectService.importProject(request)) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Platform GITHUB not supported"); | |||
} | |||
@Test | |||
void createImportedProject_whenAlmIsSupportedAndNoNewCodeDefinitionDefined_shouldCreateProject() { | |||
userSession.logIn().addPermission(PROVISION_PROJECTS); | |||
DbSession dbSession = mockDbSession(); | |||
AlmSettingDto almSetting = mockAlmSetting(dbSession); | |||
DevOpsProjectCreator devOpsProjectCreator = mockDevOpsProjectCreator(almSetting); | |||
ComponentCreationData componentCreationData = mockProjectCreation(devOpsProjectCreator, dbSession); | |||
ProjectDto projectDto = mockProjectDto(componentCreationData); | |||
when(componentCreationData.mainBranchDto()).thenReturn(mock(BranchDto.class)); | |||
ProjectAlmSettingDto projectAlmSettingDto = mockProjectAlmSetting(dbSession, projectDto); | |||
ImportProjectRequest request = new ImportProjectRequest(PROJECT_KEY, PROJECT_NAME, ALM_SETTING_ID, REPOSITORY_ID, null, null, true); | |||
ImportedProject importedProject = importProjectService.importProject(request); | |||
assertThat(importedProject.projectDto()).isEqualTo(projectDto); | |||
assertThat(importedProject.projectAlmSettingDto()).isEqualTo(projectAlmSettingDto); | |||
verify(componentUpdater).commitAndIndex(dbSession, componentCreationData); | |||
} | |||
@Test | |||
void createImportedProject_whenAlmIsSupportedAndNewCodeDefinitionDefined_shouldCreateProjectAndNewCodeDefinition() { | |||
userSession.logIn().addPermission(PROVISION_PROJECTS); | |||
DbSession dbSession = mockDbSession(); | |||
AlmSettingDto almSetting = mockAlmSetting(dbSession); | |||
DevOpsProjectCreator devOpsProjectCreator = mockDevOpsProjectCreator(almSetting); | |||
ComponentCreationData componentCreationData = mockProjectCreation(devOpsProjectCreator, dbSession); | |||
ProjectDto projectDto = mockProjectDto(componentCreationData); | |||
mockBranchDto(componentCreationData); | |||
ProjectAlmSettingDto projectAlmSettingDto = mockProjectAlmSetting(dbSession, projectDto); | |||
ImportProjectRequest request = new ImportProjectRequest(PROJECT_KEY, PROJECT_NAME, ALM_SETTING_ID, REPOSITORY_ID, "NUMBER_OF_DAYS", "10", true); | |||
ImportedProject importedProject = importProjectService.importProject(request); | |||
assertThat(importedProject.projectDto()).isEqualTo(projectDto); | |||
assertThat(importedProject.projectAlmSettingDto()).isEqualTo(projectAlmSettingDto); | |||
verify(newCodeDefinitionResolver).createNewCodeDefinition( | |||
dbSession, | |||
PROJECT_UUID, | |||
MAIN_BRANCH_UUID, | |||
MAIN_BRANCH_KEY, | |||
"NUMBER_OF_DAYS", | |||
"10"); | |||
verify(componentUpdater).commitAndIndex(dbSession, componentCreationData); | |||
} | |||
private DbSession mockDbSession() { | |||
DbSession dbSession = mock(DbSession.class); | |||
when(dbClient.openSession(false)).thenReturn(dbSession); | |||
return dbSession; | |||
} | |||
private AlmSettingDto mockAlmSetting(DbSession dbSession) { | |||
AlmSettingDto almSetting = mock(AlmSettingDto.class); | |||
when(almSetting.getAlm()).thenReturn(ALM.GITHUB); | |||
when(almSetting.getUrl()).thenReturn(API_URL); | |||
when(dbClient.almSettingDao().selectByUuid(dbSession, ALM_SETTING_ID)).thenReturn(Optional.of(almSetting)); | |||
return almSetting; | |||
} | |||
private DevOpsProjectCreator mockDevOpsProjectCreator(AlmSettingDto almSetting) { | |||
DevOpsProjectCreator devOpsProjectCreator = mock(DevOpsProjectCreator.class); | |||
DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, API_URL, REPOSITORY_ID); | |||
when(devOpsProjectCreatorFactory.getDevOpsProjectCreator(almSetting, projectDescriptor)) | |||
.thenReturn(Optional.of(devOpsProjectCreator)); | |||
return devOpsProjectCreator; | |||
} | |||
private static ComponentCreationData mockProjectCreation(DevOpsProjectCreator devOpsProjectCreator, DbSession dbSession) { | |||
ComponentCreationData componentCreationData = mock(ComponentCreationData.class); | |||
when(devOpsProjectCreator.createProjectAndBindToDevOpsPlatform(eq(dbSession), any(), eq(true), eq(PROJECT_KEY), eq(PROJECT_NAME))) | |||
.thenReturn(componentCreationData); | |||
return componentCreationData; | |||
} | |||
private static ProjectDto mockProjectDto(ComponentCreationData componentCreationData) { | |||
ProjectDto projectDto = mock(ProjectDto.class); | |||
lenient().when(projectDto.getUuid()).thenReturn(PROJECT_UUID); | |||
when(componentCreationData.projectDto()).thenReturn(projectDto); | |||
return projectDto; | |||
} | |||
private static void mockBranchDto(ComponentCreationData componentCreationData) { | |||
BranchDto mainBrainDto = mock(BranchDto.class); | |||
when(mainBrainDto.getUuid()).thenReturn(MAIN_BRANCH_UUID); | |||
when(mainBrainDto.getKey()).thenReturn(MAIN_BRANCH_KEY); | |||
when(componentCreationData.mainBranchDto()).thenReturn(mainBrainDto); | |||
} | |||
private ProjectAlmSettingDto mockProjectAlmSetting(DbSession dbSession, ProjectDto projectDto) { | |||
ProjectAlmSettingDto projectAlmSetting = mock(ProjectAlmSettingDto.class); | |||
when(dbClient.projectAlmSettingDao().selectByProject(dbSession, projectDto)) | |||
.thenReturn(Optional.of(projectAlmSetting)); | |||
return projectAlmSetting; | |||
} | |||
} |
@@ -18,6 +18,7 @@ dependencies { | |||
testImplementation 'javax.servlet:javax.servlet-api' | |||
testImplementation 'org.junit.jupiter:junit-jupiter-api' | |||
testImplementation 'org.mockito:mockito-core' | |||
testImplementation 'org.mockito:mockito-junit-jupiter' | |||
testImplementation 'org.skyscreamer:jsonassert:1.5.1' | |||
testImplementation 'org.sonarsource.api.plugin:sonar-plugin-api-test-fixtures' | |||
testImplementation 'com.tngtech.java:junit-dataprovider' |
@@ -38,6 +38,8 @@ public class WebApiEndpoints { | |||
public static final String GITLAB_CONFIGURATION_ENDPOINT = DOP_TRANSLATION_DOMAIN + "/gitlab-configurations"; | |||
public static final String BOUND_PROJECTS_ENDPOINT = DOP_TRANSLATION_DOMAIN + "/bound-projects"; | |||
public static final String INTERNAL = "internal"; | |||
private WebApiEndpoints() { |
@@ -0,0 +1,49 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.projects.controller; | |||
import io.swagger.v3.oas.annotations.Operation; | |||
import javax.validation.Valid; | |||
import org.sonar.server.v2.api.projects.request.BoundProjectCreateRestRequest; | |||
import org.sonar.server.v2.api.projects.response.BoundProjectCreateRestResponse; | |||
import org.springframework.http.HttpStatus; | |||
import org.springframework.web.bind.annotation.PostMapping; | |||
import org.springframework.web.bind.annotation.RequestBody; | |||
import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.ResponseStatus; | |||
import org.springframework.web.bind.annotation.RestController; | |||
import static org.sonar.server.v2.WebApiEndpoints.BOUND_PROJECTS_ENDPOINT; | |||
@RequestMapping(BOUND_PROJECTS_ENDPOINT) | |||
@RestController | |||
public interface BoundProjectsController { | |||
@PostMapping | |||
@Operation(summary = "Create a SonarQube project with the information from the provided DevOps platform project.", description = """ | |||
Create a SonarQube project with the information from the provided DevOps platform project. | |||
Autoconfigure Pull-Request decoration mechanism. | |||
Requires the 'Create Projects' permission | |||
""") | |||
@ResponseStatus(HttpStatus.CREATED) | |||
BoundProjectCreateRestResponse createBoundProject(@Valid @RequestBody BoundProjectCreateRestRequest request); | |||
} |
@@ -0,0 +1,58 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.projects.controller; | |||
import org.sonar.server.common.project.ImportProjectRequest; | |||
import org.sonar.server.common.project.ImportProjectService; | |||
import org.sonar.server.common.project.ImportedProject; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.v2.api.projects.request.BoundProjectCreateRestRequest; | |||
import org.sonar.server.v2.api.projects.response.BoundProjectCreateRestResponse; | |||
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; | |||
public class DefaultBoundProjectsController implements BoundProjectsController { | |||
private final UserSession userSession; | |||
private final ImportProjectService importProjectService; | |||
public DefaultBoundProjectsController(UserSession userSession, ImportProjectService importProjectService) { | |||
this.userSession = userSession; | |||
this.importProjectService = importProjectService; | |||
} | |||
@Override | |||
public BoundProjectCreateRestResponse createBoundProject(BoundProjectCreateRestRequest request) { | |||
userSession.checkLoggedIn().checkPermission(PROVISION_PROJECTS); | |||
ImportedProject importedProject = importProjectService.importProject(restRequestToServiceRequest(request)); | |||
return toRestResponse(importedProject); | |||
} | |||
private static ImportProjectRequest restRequestToServiceRequest(BoundProjectCreateRestRequest request) { | |||
return new ImportProjectRequest(request.projectKey(), request.projectName(), request.devOpsPlatformSettingId(), request.repositoryIdentifier(), | |||
request.newCodeDefinitionType(), request.newCodeDefinitionValue(), request.monorepo()); | |||
} | |||
private static BoundProjectCreateRestResponse toRestResponse(ImportedProject importedProject) { | |||
return new BoundProjectCreateRestResponse(importedProject.projectDto().getUuid(), importedProject.projectAlmSettingDto().getUuid()); | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.v2.api.projects.controller; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -0,0 +1,68 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.projects.request; | |||
import io.swagger.v3.oas.annotations.media.Schema; | |||
import javax.annotation.Nullable; | |||
import javax.validation.constraints.NotEmpty; | |||
import javax.validation.constraints.NotNull; | |||
public record BoundProjectCreateRestRequest( | |||
@NotEmpty | |||
@Schema(description = "Key of the project to create") | |||
String projectKey, | |||
@NotEmpty | |||
@Schema(description = "Name of the project to create") | |||
String projectName, | |||
@NotEmpty | |||
@Schema(description = "Identifier of DevOps platform configuration to use.") | |||
String devOpsPlatformSettingId, | |||
@NotEmpty | |||
@Schema(description = "Identifier of the DevOps platform repository to import. Repository slug for GitHub, repository id for GitLab.") | |||
String repositoryIdentifier, | |||
@Nullable | |||
@Schema(description = """ | |||
Project New Code Definition Type | |||
New code definitions of the following types are allowed: | |||
- PREVIOUS_VERSION | |||
- NUMBER_OF_DAYS | |||
- REFERENCE_BRANCH - will default to the main branch. | |||
""") | |||
String newCodeDefinitionType, | |||
@Nullable | |||
@Schema(description = """ | |||
Project New Code Definition Value | |||
For each new code definition type, a different value is expected: | |||
- no value, when the new code definition type is PREVIOUS_VERSION and REFERENCE_BRANCH | |||
- a number between 1 and 90, when the new code definition type is NUMBER_OF_DAYS | |||
""") | |||
String newCodeDefinitionValue, | |||
@NotNull | |||
@Schema(description = "True if project is part of a mono repo.") | |||
Boolean monorepo | |||
) { | |||
} |
@@ -18,6 +18,6 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.newcodeperiod; | |||
package org.sonar.server.v2.api.projects.request; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -0,0 +1,31 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.projects.response; | |||
import io.swagger.v3.oas.annotations.media.Schema; | |||
public record BoundProjectCreateRestResponse( | |||
@Schema(description = "The identifier of the created project") | |||
String projectId, | |||
@Schema(description = "The identifier of the binding between the created project and the DevOps platform project") | |||
String bindingId) { | |||
} |
@@ -0,0 +1,23 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.v2.api.projects.response; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -32,6 +32,7 @@ import org.sonar.server.common.health.WebServerStatusNodeCheck; | |||
import org.sonar.server.common.management.ManagedInstanceChecker; | |||
import org.sonar.server.common.platform.LivenessChecker; | |||
import org.sonar.server.common.platform.LivenessCheckerImpl; | |||
import org.sonar.server.common.project.ImportProjectService; | |||
import org.sonar.server.common.rule.service.RuleService; | |||
import org.sonar.server.common.text.MacroInterpreter; | |||
import org.sonar.server.common.user.service.UserService; | |||
@@ -46,6 +47,8 @@ import org.sonar.server.v2.api.group.controller.DefaultGroupController; | |||
import org.sonar.server.v2.api.group.controller.GroupController; | |||
import org.sonar.server.v2.api.membership.controller.DefaultGroupMembershipController; | |||
import org.sonar.server.v2.api.membership.controller.GroupMembershipController; | |||
import org.sonar.server.v2.api.projects.controller.DefaultBoundProjectsController; | |||
import org.sonar.server.v2.api.projects.controller.BoundProjectsController; | |||
import org.sonar.server.v2.api.rule.controller.DefaultRuleController; | |||
import org.sonar.server.v2.api.rule.controller.RuleController; | |||
import org.sonar.server.v2.api.rule.converter.RuleRestResponseGenerator; | |||
@@ -100,7 +103,6 @@ public class PlatformLevel4WebConfig { | |||
return new DefaultGroupController(userSession, dbClient, groupService, managedInstanceChecker); | |||
} | |||
@Bean | |||
public GroupMembershipController groupMembershipsController(UserSession userSession, | |||
GroupMembershipService groupMembershipService, ManagedInstanceChecker managedInstanceChecker) { | |||
@@ -129,4 +131,10 @@ public class PlatformLevel4WebConfig { | |||
return new DefaultGitlabConfigurationController(userSession, gitlabConfigurationService); | |||
} | |||
@Bean | |||
public BoundProjectsController importedProjectsController(UserSession userSession, ImportProjectService importProjectService) { | |||
return new DefaultBoundProjectsController( | |||
userSession, importProjectService); | |||
} | |||
} |
@@ -0,0 +1,151 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2024 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.v2.api.projects.controller; | |||
import org.junit.Rule; | |||
import org.junit.jupiter.api.Test; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.common.project.ImportProjectRequest; | |||
import org.sonar.server.common.project.ImportProjectService; | |||
import org.sonar.server.common.project.ImportedProject; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.v2.api.ControllerTester; | |||
import org.springframework.http.MediaType; | |||
import org.springframework.test.web.servlet.MockMvc; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS; | |||
import static org.sonar.server.v2.WebApiEndpoints.BOUND_PROJECTS_ENDPOINT; | |||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |||
class DefaultBoundProjectsControllerTest { | |||
private static final String PROJECT_UUID = "project-uuid"; | |||
private static final String PROJECT_ALM_SETTING_UUID = "project-alm-setting-uuid"; | |||
private static final String REPOSITORY_ID = "repository-id"; | |||
private static final String PROJECT_KEY = "project-key"; | |||
private static final String PROJECT_NAME = "project-name"; | |||
private static final String ALM_SETTING_ID = "alm-setting-id"; | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
private final ImportProjectService importProjectService = mock(); | |||
private final MockMvc mockMvc = ControllerTester.getMockMvc( | |||
new DefaultBoundProjectsController( | |||
userSession, importProjectService)); | |||
@Test | |||
void createBoundProject_whenUserDoesntHaveCreateProjectPermission_returnsForbidden() throws Exception { | |||
userSession.logIn(); | |||
mockMvc.perform( | |||
post(BOUND_PROJECTS_ENDPOINT) | |||
.contentType(MediaType.APPLICATION_JSON) | |||
.content(""" | |||
{ | |||
"projectKey": "project-key", | |||
"projectName": "project-name", | |||
"devOpsPlatformSettingId": "alm-setting-id", | |||
"repositoryIdentifier": "repository-id", | |||
"monorepo": true | |||
} | |||
""") | |||
) | |||
.andExpect(status().isForbidden()); | |||
} | |||
@Test | |||
void createdBoundProject_whenImportProjectServiceThrowsIllegalArgumentExceptions_returnsBadRequest() throws Exception { | |||
userSession.logIn().addPermission(PROVISION_PROJECTS); | |||
when(importProjectService.importProject(any())) | |||
.thenThrow(new IllegalArgumentException("Error message")); | |||
mockMvc.perform( | |||
post(BOUND_PROJECTS_ENDPOINT) | |||
.contentType(MediaType.APPLICATION_JSON) | |||
.content(""" | |||
{ | |||
"projectKey": "project-key", | |||
"projectName": "project-name", | |||
"devOpsPlatformSettingId": "alm-setting-id", | |||
"repositoryIdentifier": "repository-id", | |||
"monorepo": true | |||
} | |||
""")) | |||
.andExpectAll( | |||
status().isBadRequest(), | |||
content().json(""" | |||
{ | |||
"message": "Error message" | |||
} | |||
""")); | |||
} | |||
@Test | |||
void createBoundProject_whenProjectIsCreatedSuccessfully_returnResponse() throws Exception { | |||
userSession.logIn().addPermission(PROVISION_PROJECTS); | |||
ProjectDto projectDto = mock(ProjectDto.class); | |||
when(projectDto.getUuid()).thenReturn(PROJECT_UUID); | |||
ProjectAlmSettingDto projectAlmSettingDto = mock(ProjectAlmSettingDto.class); | |||
when(projectAlmSettingDto.getUuid()).thenReturn(PROJECT_ALM_SETTING_UUID); | |||
when(importProjectService.importProject(new ImportProjectRequest( | |||
PROJECT_KEY, | |||
PROJECT_NAME, | |||
ALM_SETTING_ID, | |||
REPOSITORY_ID, | |||
"NUMBER_OF_DAYS", | |||
"10", | |||
true))) | |||
.thenReturn(new ImportedProject( | |||
projectDto, | |||
projectAlmSettingDto)); | |||
mockMvc.perform( | |||
post(BOUND_PROJECTS_ENDPOINT) | |||
.contentType(MediaType.APPLICATION_JSON) | |||
.content(""" | |||
{ | |||
"projectKey": "project-key", | |||
"projectName": "project-name", | |||
"devOpsPlatformSettingId": "alm-setting-id", | |||
"repositoryIdentifier": "repository-id", | |||
"newCodeDefinitionType": "NUMBER_OF_DAYS", | |||
"newCodeDefinitionValue": "10", | |||
"monorepo": true | |||
} | |||
""")) | |||
.andExpectAll( | |||
status().isCreated(), | |||
content().json(""" | |||
{ | |||
"projectId": "project-uuid", | |||
"bindingId": "project-alm-setting-uuid" | |||
} | |||
""")); | |||
} | |||
} |
@@ -54,6 +54,7 @@ import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.common.almintegration.ProjectKeyGenerator; | |||
import org.sonar.server.common.almsettings.github.GithubProjectCreatorFactory; | |||
import org.sonar.server.common.component.ComponentUpdater; | |||
import org.sonar.server.common.project.ImportProjectService; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.es.IndexersImpl; | |||
import org.sonar.server.es.TestIndexers; | |||
@@ -144,8 +145,10 @@ public class ImportGithubProjectActionIT { | |||
private final GithubProjectCreatorFactory gitHubProjectCreatorFactory = new GithubProjectCreatorFactory(db.getDbClient(), | |||
null, appClient, projectKeyGenerator, userSession, projectCreator, gitHubSettings, githubPermissionConverter, userPermissionUpdater, permissionService, | |||
managedProjectService); | |||
private final WsActionTester ws = new WsActionTester(new ImportGithubProjectAction(db.getDbClient(), userSession, | |||
componentUpdater, importHelper, newCodeDefinitionResolver, defaultBranchNameResolver, gitHubProjectCreatorFactory)); | |||
private final ImportProjectService importProjectService = new ImportProjectService(db.getDbClient(), gitHubProjectCreatorFactory, userSession, componentUpdater, | |||
newCodeDefinitionResolver); | |||
private final WsActionTester ws = new WsActionTester(new ImportGithubProjectAction(importProjectService, importHelper)); | |||
@Before | |||
public void before() { |
@@ -44,6 +44,7 @@ import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.common.almintegration.ProjectKeyGenerator; | |||
import org.sonar.server.common.almsettings.gitlab.GitlabProjectCreatorFactory; | |||
import org.sonar.server.common.component.ComponentUpdater; | |||
import org.sonar.server.common.project.ImportProjectService; | |||
import org.sonar.server.es.TestIndexers; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.favorite.FavoriteUpdater; | |||
@@ -105,8 +106,10 @@ public class ImportGitLabProjectActionIT { | |||
private final ProjectCreator projectCreator = new ProjectCreator(userSession, projectDefaultVisibility, componentUpdater); | |||
private final GitlabProjectCreatorFactory gitlabProjectCreatorFactory = new GitlabProjectCreatorFactory(db.getDbClient(), projectKeyGenerator, projectCreator, | |||
gitlabApplicationClient, userSession); | |||
private final ImportGitLabProjectAction importGitLabProjectAction = new ImportGitLabProjectAction( | |||
db.getDbClient(), userSession, componentUpdater, importHelper, newCodeDefinitionResolver, gitlabProjectCreatorFactory); | |||
private final ImportProjectService importProjectService = new ImportProjectService(db.getDbClient(), gitlabProjectCreatorFactory, userSession, componentUpdater, | |||
newCodeDefinitionResolver); | |||
private final ImportGitLabProjectAction importGitLabProjectAction = new ImportGitLabProjectAction(importProjectService, importHelper); | |||
private final WsActionTester ws = new WsActionTester(importGitLabProjectAction); | |||
@Before |
@@ -19,40 +19,24 @@ | |||
*/ | |||
package org.sonar.server.almintegration.ws.github; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import javax.inject.Inject; | |||
import org.sonar.api.server.ws.Change; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.alm.setting.ALM; | |||
import org.sonar.db.alm.setting.AlmSettingDto; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.project.CreationMethod; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.common.almsettings.DevOpsProjectCreator; | |||
import org.sonar.server.common.almsettings.DevOpsProjectDescriptor; | |||
import org.sonar.server.common.almsettings.github.GithubProjectCreatorFactory; | |||
import org.sonar.server.component.ComponentCreationData; | |||
import org.sonar.server.common.component.ComponentUpdater; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver; | |||
import org.sonar.server.project.DefaultBranchNameResolver; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.common.project.ImportProjectRequest; | |||
import org.sonar.server.common.project.ImportProjectService; | |||
import org.sonar.server.common.project.ImportedProject; | |||
import org.sonarqube.ws.Projects; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.db.project.CreationMethod.getCreationMethod; | |||
import static org.sonar.db.project.CreationMethod.Category.ALM_IMPORT; | |||
import static org.sonar.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING; | |||
import static org.sonar.server.almintegration.ws.ImportHelper.toCreateResponse; | |||
import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION; | |||
import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION; | |||
import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.checkNewCodeDefinitionParam; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE; | |||
@@ -60,30 +44,13 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_COD | |||
public class ImportGithubProjectAction implements AlmIntegrationsWsAction { | |||
public static final String PARAM_REPOSITORY_KEY = "repositoryKey"; | |||
private final DbClient dbClient; | |||
private final UserSession userSession; | |||
private final ComponentUpdater componentUpdater; | |||
private final ImportProjectService importProjectService; | |||
private final ImportHelper importHelper; | |||
private final NewCodeDefinitionResolver newCodeDefinitionResolver; | |||
private final DefaultBranchNameResolver defaultBranchNameResolver; | |||
private final GithubProjectCreatorFactory githubProjectCreatorFactory; | |||
@Inject | |||
public ImportGithubProjectAction(DbClient dbClient, UserSession userSession, | |||
ComponentUpdater componentUpdater, ImportHelper importHelper, | |||
NewCodeDefinitionResolver newCodeDefinitionResolver, | |||
DefaultBranchNameResolver defaultBranchNameResolver, GithubProjectCreatorFactory githubProjectCreatorFactory) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.componentUpdater = componentUpdater; | |||
public ImportGithubProjectAction(ImportProjectService importProjectService, ImportHelper importHelper) { | |||
this.importProjectService = importProjectService; | |||
this.importHelper = importHelper; | |||
this.newCodeDefinitionResolver = newCodeDefinitionResolver; | |||
this.defaultBranchNameResolver = defaultBranchNameResolver; | |||
this.githubProjectCreatorFactory = githubProjectCreatorFactory; | |||
} | |||
@Override | |||
@@ -128,34 +95,18 @@ public class ImportGithubProjectAction implements AlmIntegrationsWsAction { | |||
private Projects.CreateWsResponse doHandle(Request request) { | |||
importHelper.checkProvisionProjectPermission(); | |||
AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.GITHUB); | |||
String repositoryKey = request.mandatoryParam(PARAM_REPOSITORY_KEY); | |||
String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE); | |||
String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
String repositoryKey = request.mandatoryParam(PARAM_REPOSITORY_KEY); | |||
ImportedProject importedProject = importProjectService.importProject(toServiceRequest(almSettingDto, repositoryKey, newCodeDefinitionType, newCodeDefinitionValue)); | |||
String url = requireNonNull(almSettingDto.getUrl(), "DevOps Platform url cannot be null"); | |||
DevOpsProjectDescriptor devOpsProjectDescriptor = new DevOpsProjectDescriptor(ALM.GITHUB, url, repositoryKey); | |||
return ImportHelper.toCreateResponse(importedProject.projectDto()); | |||
DevOpsProjectCreator devOpsProjectCreator = githubProjectCreatorFactory.getDevOpsProjectCreator(almSettingDto, devOpsProjectDescriptor) | |||
.orElseThrow(() -> BadRequestException.create("GitHub DevOps platform configuration not found.")); | |||
CreationMethod creationMethod = getCreationMethod(ALM_IMPORT, userSession.isAuthenticatedBrowserSession()); | |||
ComponentCreationData componentCreationData = devOpsProjectCreator.createProjectAndBindToDevOpsPlatform(dbSession, creationMethod, false, null, null); | |||
checkNewCodeDefinitionParam(newCodeDefinitionType, newCodeDefinitionValue); | |||
ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow(); | |||
BranchDto mainBranchDto = Optional.ofNullable(componentCreationData.mainBranchDto()).orElseThrow(); | |||
if (newCodeDefinitionType != null) { | |||
newCodeDefinitionResolver.createNewCodeDefinition(dbSession, projectDto.getUuid(), mainBranchDto.getUuid(), | |||
Optional.ofNullable(mainBranchDto.getKey()).orElse(defaultBranchNameResolver.getEffectiveMainBranchName()), | |||
newCodeDefinitionType, newCodeDefinitionValue); | |||
} | |||
} | |||
componentUpdater.commitAndIndex(dbSession, componentCreationData); | |||
return toCreateResponse(projectDto); | |||
} | |||
private static ImportProjectRequest toServiceRequest(AlmSettingDto almSettingDto, String githubRepositoryKey, @Nullable String newCodeDefinitionType, | |||
@Nullable String newCodeDefinitionValue) { | |||
return new ImportProjectRequest(null, null, almSettingDto.getUuid(), githubRepositoryKey, newCodeDefinitionType, newCodeDefinitionValue, false); | |||
} | |||
} |
@@ -19,37 +19,24 @@ | |||
*/ | |||
package org.sonar.server.almintegration.ws.gitlab; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import javax.inject.Inject; | |||
import org.sonar.api.server.ws.Change; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.alm.setting.ALM; | |||
import org.sonar.db.alm.setting.AlmSettingDto; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction; | |||
import org.sonar.server.almintegration.ws.ImportHelper; | |||
import org.sonar.server.common.almsettings.DevOpsProjectCreator; | |||
import org.sonar.server.common.almsettings.DevOpsProjectDescriptor; | |||
import org.sonar.server.common.almsettings.gitlab.GitlabProjectCreatorFactory; | |||
import org.sonar.server.component.ComponentCreationData; | |||
import org.sonar.server.common.component.ComponentUpdater; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.common.project.ImportProjectRequest; | |||
import org.sonar.server.common.project.ImportProjectService; | |||
import org.sonar.server.common.project.ImportedProject; | |||
import org.sonarqube.ws.Projects.CreateWsResponse; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.db.project.CreationMethod.getCreationMethod; | |||
import static org.sonar.db.project.CreationMethod.Category.ALM_IMPORT; | |||
import static org.sonar.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING; | |||
import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION; | |||
import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION; | |||
import static org.sonar.server.common.newcodeperiod.NewCodeDefinitionResolver.checkNewCodeDefinitionParam; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE; | |||
@@ -58,23 +45,13 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { | |||
public static final String PARAM_GITLAB_PROJECT_ID = "gitlabProjectId"; | |||
private final DbClient dbClient; | |||
private final UserSession userSession; | |||
private final ComponentUpdater componentUpdater; | |||
private final ImportProjectService importProjectService; | |||
private final ImportHelper importHelper; | |||
private final NewCodeDefinitionResolver newCodeDefinitionResolver; | |||
private final GitlabProjectCreatorFactory projectCreatorFactory; | |||
@Inject | |||
public ImportGitLabProjectAction(DbClient dbClient, UserSession userSession, | |||
ComponentUpdater componentUpdater, ImportHelper importHelper, NewCodeDefinitionResolver newCodeDefinitionResolver, | |||
GitlabProjectCreatorFactory projectCreatorFactory) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.componentUpdater = componentUpdater; | |||
public ImportGitLabProjectAction(ImportProjectService importProjectService, ImportHelper importHelper) { | |||
this.importProjectService = importProjectService; | |||
this.importHelper = importHelper; | |||
this.newCodeDefinitionResolver = newCodeDefinitionResolver; | |||
this.projectCreatorFactory = projectCreatorFactory; | |||
} | |||
@Override | |||
@@ -112,33 +89,17 @@ public class ImportGitLabProjectAction implements AlmIntegrationsWsAction { | |||
private CreateWsResponse doHandle(Request request) { | |||
importHelper.checkProvisionProjectPermission(); | |||
AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.GITLAB); | |||
String gitlabProjectId = request.mandatoryParam(PARAM_GITLAB_PROJECT_ID); | |||
String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE); | |||
String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE); | |||
ImportedProject importedProject = importProjectService.importProject(toServiceRequest(almSettingDto, gitlabProjectId, newCodeDefinitionType, newCodeDefinitionValue)); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
AlmSettingDto almSettingDto = importHelper.getAlmSettingDtoForAlm(request, ALM.GITLAB); | |||
String gitlabProjectId = request.mandatoryParam(PARAM_GITLAB_PROJECT_ID); | |||
String gitlabUrl = requireNonNull(almSettingDto.getUrl(), "DevOps Platform gitlabUrl cannot be null"); | |||
DevOpsProjectDescriptor projectDescriptor = new DevOpsProjectDescriptor(ALM.GITLAB, gitlabUrl, gitlabProjectId); | |||
DevOpsProjectCreator projectCreator = projectCreatorFactory.getDevOpsProjectCreator(almSettingDto, projectDescriptor) | |||
.orElseThrow(() -> BadRequestException.create("Gitlab DevOps platform configuration not found")); | |||
ComponentCreationData componentCreationData = projectCreator.createProjectAndBindToDevOpsPlatform(dbSession, | |||
getCreationMethod(ALM_IMPORT, userSession.isAuthenticatedBrowserSession()), false, null, null); | |||
ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow(); | |||
BranchDto mainBranchDto = Optional.ofNullable(componentCreationData.mainBranchDto()).orElseThrow(); | |||
checkNewCodeDefinitionParam(newCodeDefinitionType, newCodeDefinitionValue); | |||
if (newCodeDefinitionType != null) { | |||
newCodeDefinitionResolver.createNewCodeDefinition(dbSession, projectDto.getUuid(), mainBranchDto.getUuid(), | |||
mainBranchDto.getKey(), newCodeDefinitionType, newCodeDefinitionValue); | |||
} | |||
return ImportHelper.toCreateResponse(importedProject.projectDto()); | |||
} | |||
componentUpdater.commitAndIndex(dbSession, componentCreationData); | |||
return ImportHelper.toCreateResponse(projectDto); | |||
} | |||
private static ImportProjectRequest toServiceRequest(AlmSettingDto almSettingDto, String gitlabProjectId, @Nullable String newCodeDefinitionType, | |||
@Nullable String newCodeDefinitionValue) { | |||
return new ImportProjectRequest(null, null, almSettingDto.getUuid(), gitlabProjectId, newCodeDefinitionType, newCodeDefinitionValue, false); | |||
} | |||
} |
@@ -20,6 +20,7 @@ | |||
package org.sonar.server.project.ws; | |||
import org.sonar.core.platform.Module; | |||
import org.sonar.server.common.project.ImportProjectService; | |||
import org.sonar.server.common.project.ProjectCreator; | |||
import org.sonar.server.project.ProjectDefaultVisibility; | |||
import org.sonar.server.project.ProjectLifeCycleListenersImpl; | |||
@@ -33,6 +34,7 @@ public class ProjectsWsModule extends Module { | |||
@Override | |||
protected void configureModule() { | |||
add( | |||
ImportProjectService.class, | |||
ProjectDefaultVisibility.class, | |||
ProjectFinder.class, | |||
ProjectLifeCycleListenersImpl.class, |
@@ -29,6 +29,6 @@ public class ProjectsWsModuleTest { | |||
public void verify_count_of_added_components_on_SonarQube() { | |||
ListContainer container = new ListContainer(); | |||
new ProjectsWsModule().configure(container); | |||
assertThat(container.getAddedObjects()).hasSize(14); | |||
assertThat(container.getAddedObjects()).hasSize(15); | |||
} | |||
} |