@@ -0,0 +1,36 @@ | |||
/* | |||
* 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.projectbindings.service; | |||
import javax.annotation.Nullable; | |||
public record ProjectBindingInformation( | |||
String id, | |||
String devOpsPlatformSettingId, | |||
String projectId, | |||
String projectKey, | |||
@Nullable String repository, | |||
@Nullable String slug) { | |||
} |
@@ -20,7 +20,11 @@ | |||
package org.sonar.server.common.projectbindings.service; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import java.util.function.Function; | |||
import java.util.stream.Collectors; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
@@ -28,6 +32,8 @@ import org.sonar.db.alm.setting.ProjectAlmSettingQuery; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.common.SearchResults; | |||
import static java.util.function.Function.identity; | |||
public class ProjectBindingsService { | |||
private final DbClient dbClient; | |||
@@ -42,14 +48,14 @@ public class ProjectBindingsService { | |||
} | |||
} | |||
public SearchResults<ProjectAlmSettingDto> findProjectBindingsByRequest(ProjectBindingsSearchRequest request) { | |||
public SearchResults<ProjectBindingInformation> findProjectBindingsByRequest(ProjectBindingsSearchRequest request) { | |||
ProjectAlmSettingQuery query = buildProjectAlmSettingQuery(request); | |||
try (DbSession session = dbClient.openSession(false)) { | |||
int total = dbClient.projectAlmSettingDao().countProjectAlmSettings(session, query); | |||
if (request.pageSize() == 0) { | |||
return new SearchResults<>(List.of(), total); | |||
} | |||
List<ProjectAlmSettingDto> searchResults = performSearch(session, query, request.page(), request.pageSize()); | |||
List<ProjectBindingInformation> searchResults = performSearch(session, query, request.page(), request.pageSize()); | |||
return new SearchResults<>(searchResults, total); | |||
} | |||
} | |||
@@ -58,10 +64,24 @@ public class ProjectBindingsService { | |||
return new ProjectAlmSettingQuery(request.repository(), request.dopSettingId()); | |||
} | |||
private List<ProjectAlmSettingDto> performSearch(DbSession dbSession, ProjectAlmSettingQuery query, int page, int pageSize) { | |||
return dbClient.projectAlmSettingDao().selectProjectAlmSettings(dbSession, query, page, pageSize) | |||
private List<ProjectBindingInformation> performSearch(DbSession dbSession, ProjectAlmSettingQuery query, int page, int pageSize) { | |||
List<ProjectAlmSettingDto> projectAlmSettings = dbClient.projectAlmSettingDao().selectProjectAlmSettings(dbSession, query, page, pageSize) | |||
.stream() | |||
.toList(); | |||
Set<String> projectUuids = projectAlmSettings.stream().map(ProjectAlmSettingDto::getProjectUuid).collect(Collectors.toSet()); | |||
List<ProjectDto> projectDtos = dbClient.projectDao().selectByUuids(dbSession, projectUuids); | |||
Map<String, ProjectDto> projectUuidsToProject = projectDtos.stream().collect(Collectors.toMap(ProjectDto::getUuid, identity())); | |||
return projectAlmSettings.stream().map(projectAlmSettingDtoToProjectBindingInformation(projectUuidsToProject)).toList(); | |||
} | |||
private static Function<ProjectAlmSettingDto, ProjectBindingInformation> projectAlmSettingDtoToProjectBindingInformation(Map<String, ProjectDto> projectUuidToProject) { | |||
return projectAlmSettingDto -> { | |||
ProjectDto projectDto = projectUuidToProject.get(projectAlmSettingDto.getProjectUuid()); | |||
return new ProjectBindingInformation(projectAlmSettingDto.getUuid(), projectAlmSettingDto.getAlmSettingUuid(), projectAlmSettingDto.getProjectUuid(), projectDto.getKey(), | |||
projectAlmSettingDto.getAlmRepo(), projectAlmSettingDto.getAlmSlug()); | |||
}; | |||
} | |||
public Optional<ProjectDto> findProjectFromBinding(ProjectAlmSettingDto projectAlmSettingDto) { |
@@ -19,12 +19,13 @@ | |||
*/ | |||
package org.sonar.server.common.projectbindings.service; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import org.junit.jupiter.api.BeforeEach; | |||
import org.junit.jupiter.api.Test; | |||
import org.junit.jupiter.api.extension.ExtendWith; | |||
import org.mockito.Answers; | |||
import org.mockito.ArgumentCaptor; | |||
import org.mockito.Captor; | |||
import org.mockito.InjectMocks; | |||
@@ -32,9 +33,9 @@ import org.mockito.Mock; | |||
import org.mockito.junit.jupiter.MockitoExtension; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDao; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingQuery; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.common.SearchResults; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -55,7 +56,7 @@ public class ProjectBindingsServiceTest { | |||
@Mock | |||
private DbSession dbSession; | |||
@Mock | |||
@Mock(answer = Answers.RETURNS_DEEP_STUBS) | |||
private DbClient dbClient; | |||
@InjectMocks | |||
@@ -67,7 +68,6 @@ public class ProjectBindingsServiceTest { | |||
@BeforeEach | |||
void setup() { | |||
when(dbClient.openSession(false)).thenReturn(dbSession); | |||
when(dbClient.projectAlmSettingDao()).thenReturn(mock(ProjectAlmSettingDao.class)); | |||
} | |||
@Test | |||
@@ -87,21 +87,30 @@ public class ProjectBindingsServiceTest { | |||
@Test | |||
void findProjectBindingsByRequest_whenResults_returnsThem() { | |||
ProjectAlmSettingDto dto1 = mock(); | |||
ProjectAlmSettingDto dto2 = mock(); | |||
List<ProjectAlmSettingDto> expectedResults = List.of(dto1, dto2); | |||
ProjectAlmSettingDto projectAlmSettingDto1 = mockProjectAlmSettingDto("1"); | |||
ProjectAlmSettingDto projectAlmSettingDto2 = mockProjectAlmSettingDto("2"); | |||
List<ProjectAlmSettingDto> projectAlmSettings = List.of(projectAlmSettingDto1, projectAlmSettingDto2); | |||
when(dbClient.projectAlmSettingDao().selectProjectAlmSettings(eq(dbSession), daoQueryCaptor.capture(), eq(12), eq(42))) | |||
.thenReturn(expectedResults); | |||
.thenReturn(projectAlmSettings); | |||
when(dbClient.projectAlmSettingDao().countProjectAlmSettings(eq(dbSession), any())) | |||
.thenReturn(expectedResults.size()); | |||
.thenReturn(projectAlmSettings.size()); | |||
ProjectDto mockProjectDto1 = mockProjectDto("1"); | |||
ProjectDto mockProjectDto2 = mockProjectDto("2"); | |||
when(dbClient.projectDao().selectByUuids(dbSession, Set.of("projectUuid_1", "projectUuid_2"))) | |||
.thenReturn(List.of(mockProjectDto1, mockProjectDto2)); | |||
ProjectBindingsSearchRequest request = new ProjectBindingsSearchRequest(REPO_QUERY, ALM_SETTING_UUID_QUERY, 12, 42); | |||
SearchResults<ProjectAlmSettingDto> actualResults = underTest.findProjectBindingsByRequest(request); | |||
List<ProjectBindingInformation> expectedResults = List.of(projectBindingInformation("1"), projectBindingInformation("2")); | |||
SearchResults<ProjectBindingInformation> actualResults = underTest.findProjectBindingsByRequest(request); | |||
assertThat(daoQueryCaptor.getValue().repository()).isEqualTo(REPO_QUERY); | |||
assertThat(daoQueryCaptor.getValue().almSettingUuid()).isEqualTo(ALM_SETTING_UUID_QUERY); | |||
assertThat(actualResults.total()).isEqualTo(expectedResults.size()); | |||
assertThat(actualResults.total()).isEqualTo(projectAlmSettings.size()); | |||
assertThat(actualResults.searchResults()).containsExactlyInAnyOrderElementsOf(expectedResults); | |||
} | |||
@@ -111,7 +120,7 @@ public class ProjectBindingsServiceTest { | |||
.thenReturn(12); | |||
ProjectBindingsSearchRequest request = new ProjectBindingsSearchRequest(null, null, 42, 0); | |||
SearchResults<ProjectAlmSettingDto> actualResults = underTest.findProjectBindingsByRequest(request); | |||
SearchResults<ProjectBindingInformation> actualResults = underTest.findProjectBindingsByRequest(request); | |||
assertThat(actualResults.total()).isEqualTo(12); | |||
assertThat(actualResults.searchResults()).isEmpty(); | |||
@@ -119,4 +128,30 @@ public class ProjectBindingsServiceTest { | |||
verify(dbClient.projectAlmSettingDao(), never()).selectProjectAlmSettings(eq(dbSession), any(), anyInt(), anyInt()); | |||
} | |||
private static ProjectAlmSettingDto mockProjectAlmSettingDto(String i) { | |||
ProjectAlmSettingDto dto = mock(); | |||
when(dto.getUuid()).thenReturn("uuid_" + i); | |||
when(dto.getAlmSettingUuid()).thenReturn("almSettingUuid_" + i); | |||
when(dto.getProjectUuid()).thenReturn("projectUuid_" + i); | |||
when(dto.getAlmRepo()).thenReturn("almRepo_" + i); | |||
when(dto.getAlmSlug()).thenReturn("almSlug_" + i); | |||
return dto; | |||
} | |||
private static ProjectDto mockProjectDto(String i) { | |||
ProjectDto dto = mock(); | |||
when(dto.getUuid()).thenReturn("projectUuid_" + i); | |||
when(dto.getKey()).thenReturn("projectKey_" + i); | |||
return dto; | |||
} | |||
private static ProjectBindingInformation projectBindingInformation(String i) { | |||
return new ProjectBindingInformation("uuid_" + i, | |||
"almSettingUuid_" + i, | |||
"projectUuid_" + i, | |||
"projectKey_" + i, | |||
"almRepo_" + i, | |||
"almSlug_" + i); | |||
} | |||
} |
@@ -24,6 +24,7 @@ import java.util.Optional; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.common.SearchResults; | |||
import org.sonar.server.common.projectbindings.service.ProjectBindingInformation; | |||
import org.sonar.server.common.projectbindings.service.ProjectBindingsSearchRequest; | |||
import org.sonar.server.common.projectbindings.service.ProjectBindingsService; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
@@ -54,34 +55,44 @@ public class DefaultProjectBindingsController implements ProjectBindingsControll | |||
ProjectDto projectDto = projectBindingsService.findProjectFromBinding(projectAlmSettingDto.get()) | |||
.orElseThrow(() -> new IllegalStateException(String.format("Project (uuid '%s') not found for binding '%s'", projectAlmSettingDto.get().getProjectUuid(), id))); | |||
userSession.checkEntityPermission(USER, projectDto); | |||
return toProjectBinding(projectAlmSettingDto.get()); | |||
return toProjectBinding(projectDto, projectAlmSettingDto.get()); | |||
} else { | |||
throw new NotFoundException(String.format("Project binding '%s' not found", id)); | |||
} | |||
} | |||
private static ProjectBinding toProjectBinding(ProjectDto projectDto, ProjectAlmSettingDto projectAlmSettingDto) { | |||
return new ProjectBinding( | |||
projectAlmSettingDto.getUuid(), | |||
projectAlmSettingDto.getAlmSettingUuid(), | |||
projectAlmSettingDto.getProjectUuid(), | |||
projectDto.getKey(), | |||
projectAlmSettingDto.getAlmRepo(), | |||
projectAlmSettingDto.getAlmSlug()); | |||
} | |||
@Override | |||
public ProjectBindingsSearchRestResponse searchProjectBindings(ProjectBindingsSearchRestRequest restRequest, RestPage restPage) { | |||
userSession.checkLoggedIn().checkPermission(PROVISION_PROJECTS); | |||
ProjectBindingsSearchRequest serviceRequest = new ProjectBindingsSearchRequest(restRequest.repository(), restRequest.dopSettingId(), restPage.pageIndex(), restPage.pageSize()); | |||
SearchResults<ProjectAlmSettingDto> searchResults = projectBindingsService.findProjectBindingsByRequest(serviceRequest); | |||
SearchResults<ProjectBindingInformation> searchResults = projectBindingsService.findProjectBindingsByRequest(serviceRequest); | |||
List<ProjectBinding> projectBindings = toProjectBindings(searchResults); | |||
return new ProjectBindingsSearchRestResponse(projectBindings, new PageRestResponse(restPage.pageIndex(), restPage.pageSize(), searchResults.total())); | |||
} | |||
private static List<ProjectBinding> toProjectBindings(SearchResults<ProjectAlmSettingDto> searchResults) { | |||
private static List<ProjectBinding> toProjectBindings(SearchResults<ProjectBindingInformation> searchResults) { | |||
return searchResults.searchResults().stream() | |||
.map(DefaultProjectBindingsController::toProjectBinding) | |||
.toList(); | |||
} | |||
private static ProjectBinding toProjectBinding(ProjectAlmSettingDto dto) { | |||
private static ProjectBinding toProjectBinding(ProjectBindingInformation projectBindingInformation) { | |||
return new ProjectBinding( | |||
dto.getUuid(), | |||
dto.getAlmSettingUuid(), | |||
dto.getProjectUuid(), | |||
dto.getAlmRepo(), | |||
dto.getAlmSlug() | |||
); | |||
projectBindingInformation.id(), | |||
projectBindingInformation.devOpsPlatformSettingId(), | |||
projectBindingInformation.projectId(), | |||
projectBindingInformation.projectKey(), | |||
projectBindingInformation.repository(), | |||
projectBindingInformation.slug()); | |||
} | |||
} |
@@ -28,11 +28,14 @@ public record ProjectBinding ( | |||
String id, | |||
@NotNull | |||
String dopSettings, | |||
String devOpsPlatformSettingId, | |||
@NotNull | |||
String projectId, | |||
@NotNull | |||
String projectKey, | |||
@Nullable | |||
String repository, | |||
@@ -27,6 +27,7 @@ import org.mockito.ArgumentCaptor; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDto; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.common.SearchResults; | |||
import org.sonar.server.common.projectbindings.service.ProjectBindingInformation; | |||
import org.sonar.server.common.projectbindings.service.ProjectBindingsSearchRequest; | |||
import org.sonar.server.common.projectbindings.service.ProjectBindingsService; | |||
import org.sonar.server.tester.UserSessionRule; | |||
@@ -112,7 +113,10 @@ class DefaultProjectBindingsControllerTest { | |||
@Test | |||
void getProjectBinding_whenProjectBindingAndPermissions_returnsIt() throws Exception { | |||
ProjectAlmSettingDto projectAlmSettingDto = mockProjectAlmSettingDto("1"); | |||
ProjectDto projectDto = mock(); | |||
when(projectDto.getKey()).thenReturn("projectKey_1"); | |||
userSession.logIn().addProjectPermission(ADMIN, projectDto); | |||
when(projectBindingsService.findProjectBindingByUuid(UUID)).thenReturn(Optional.of(projectAlmSettingDto)); | |||
when(projectBindingsService.findProjectFromBinding(projectAlmSettingDto)).thenReturn(Optional.ofNullable(projectDto)); | |||
@@ -124,8 +128,9 @@ class DefaultProjectBindingsControllerTest { | |||
content().json(""" | |||
{ | |||
"id": "uuid_1", | |||
"dopSettings": "almSettingUuid_1", | |||
"devOpsPlatformSettingId": "almSettingUuid_1", | |||
"projectId": "projectUuid_1", | |||
"projectKey": "projectKey_1", | |||
"repository": "almRepo_1", | |||
"slug": "almSlug_1" | |||
} | |||
@@ -175,10 +180,10 @@ class DefaultProjectBindingsControllerTest { | |||
void searchProjectBindings_whenResultsFound_shouldReturnsThem() throws Exception { | |||
userSession.logIn().addPermission(PROVISION_PROJECTS); | |||
ProjectAlmSettingDto dto1 = mockProjectAlmSettingDto("1"); | |||
ProjectAlmSettingDto dto2 = mockProjectAlmSettingDto("2"); | |||
ProjectBindingInformation dto1 = projectBindingInformation("1"); | |||
ProjectBindingInformation dto2 = projectBindingInformation("2"); | |||
List<ProjectAlmSettingDto> expectedResults = List.of(dto1, dto2); | |||
List<ProjectBindingInformation> expectedResults = List.of(dto1, dto2); | |||
when(projectBindingsService.findProjectBindingsByRequest(any())).thenReturn(new SearchResults<>(expectedResults, expectedResults.size())); | |||
mockMvc | |||
@@ -190,33 +195,35 @@ class DefaultProjectBindingsControllerTest { | |||
.andExpectAll( | |||
status().isOk(), | |||
content().json(""" | |||
{ | |||
"projectBindings": [ | |||
{ | |||
"id": "uuid_1", | |||
"dopSettings": "almSettingUuid_1", | |||
"projectId": "projectUuid_1", | |||
"repository": "almRepo_1", | |||
"slug": "almSlug_1" | |||
}, | |||
{ | |||
"id": "uuid_2", | |||
"dopSettings": "almSettingUuid_2", | |||
"projectId": "projectUuid_2", | |||
"repository": "almRepo_2", | |||
"slug": "almSlug_2" | |||
{ | |||
"projectBindings": [ | |||
{ | |||
"id": "uuid_1", | |||
"devOpsPlatformSettingId": "almSettingUuid_1", | |||
"projectId": "projectUuid_1", | |||
"projectKey": "projectKey_1", | |||
"repository": "almRepo_1", | |||
"slug": "almSlug_1" | |||
}, | |||
{ | |||
"id": "uuid_2", | |||
"devOpsPlatformSettingId": "almSettingUuid_2", | |||
"projectId": "projectUuid_2", | |||
"projectKey": "projectKey_2", | |||
"repository": "almRepo_2", | |||
"slug": "almSlug_2" | |||
} | |||
], | |||
"page": { | |||
"pageIndex": 1, | |||
"pageSize": 100, | |||
"total": 2 | |||
} | |||
], | |||
"page": { | |||
"pageIndex": 1, | |||
"pageSize": 100, | |||
"total": 2 | |||
} | |||
} | |||
""")); | |||
""")); | |||
} | |||
private ProjectAlmSettingDto mockProjectAlmSettingDto(String i) { | |||
private static ProjectAlmSettingDto mockProjectAlmSettingDto(String i) { | |||
ProjectAlmSettingDto dto = mock(); | |||
when(dto.getUuid()).thenReturn("uuid_" + i); | |||
when(dto.getAlmSettingUuid()).thenReturn("almSettingUuid_" + i); | |||
@@ -226,4 +233,13 @@ class DefaultProjectBindingsControllerTest { | |||
return dto; | |||
} | |||
} | |||
private static ProjectBindingInformation projectBindingInformation(String i) { | |||
return new ProjectBindingInformation("uuid_" + i, | |||
"almSettingUuid_" + i, | |||
"projectUuid_" + i, | |||
"projectKey_" + i, | |||
"almRepo_" + i, | |||
"almSlug_" + i); | |||
} | |||
} |