.containsExactlyInAnyOrder(githubProject1, githubProject2);
}
+ @Test
+ public void selectByProjectUuidsAndAlm_whenGivenGithubAndProjectUuids_shouldOnlyReturnThose() {
+ AlmSettingDto githubSetting = db.almSettings().insertGitHubAlmSetting();
+ ProjectAlmSettingDto githubProject = createAlmProject(githubSetting);
+ createAlmProject(githubSetting);
+
+ AlmSettingDto gitlabSetting = db.almSettings().insertGitlabAlmSetting();
+ ProjectAlmSettingDto gitlabProject = createAlmProject(gitlabSetting);
+
+ List<ProjectAlmSettingDto> projectAlmSettingDtos =
+ underTest.selectByProjectUuidsAndAlm(dbSession, Set.of(githubProject.getProjectUuid(), gitlabProject.getProjectUuid()), ALM.GITHUB);
+
+ assertThat(projectAlmSettingDtos)
+ .usingRecursiveFieldByFieldElementComparator()
+ .containsExactlyInAnyOrder(githubProject);
+ }
+
private ProjectAlmSettingDto createAlmProject(AlmSettingDto almSettingsDto) {
ProjectDto project = db.components().insertPrivateProject().getProjectDto();
when(uuidFactory.create()).thenReturn(project.getUuid() + "_forSetting");
return getMapper(dbSession).selectByAlm(alm.getId().toLowerCase(Locale.ROOT));
}
+ public List<ProjectAlmSettingDto> selectByProjectUuidsAndAlm(DbSession dbSession, Set<String> projectUuids, ALM alm) {
+ return getMapper(dbSession).selectByProjectUuidsAndAlm(projectUuids, alm.getId().toLowerCase(Locale.ROOT));
+ }
+
public List<ProjectAlmKeyAndProject> selectAlmTypeAndUrlByProject(DbSession dbSession) {
return getMapper(dbSession).selectAlmTypeAndUrlByProject();
}
package org.sonar.db.alm.setting;
import java.util.List;
+import java.util.Set;
import javax.annotation.CheckForNull;
import org.apache.ibatis.annotations.Param;
List<ProjectAlmSettingDto> selectByAlm(@Param("alm") String alm);
+ List<ProjectAlmSettingDto> selectByProjectUuidsAndAlm(@Param("projectUuids") Set<String> projectUuids, @Param("alm") String alm);
+
List<ProjectAlmKeyAndProject> selectAlmTypeAndUrlByProject();
}
</foreach>
</select>
- <select id="selectByAlm" parameterType="string" resultType="org.sonar.db.alm.setting.ProjectAlmSettingDto">
+ <sql id="selectByAlmSql">
select <include refid="sqlColumns"/>
from
project_alm_settings p
alm_settings alm_settings on p.alm_setting_uuid = alm_settings.uuid
where
alm_settings.alm_id=#{alm, jdbcType=VARCHAR}
+ </sql>
+
+ <select id="selectByAlm" parameterType="string" resultType="org.sonar.db.alm.setting.ProjectAlmSettingDto">
+ <include refid="selectByAlmSql"/>
+ </select>
+
+ <select id="selectByProjectUuidsAndAlm" parameterType="map" resultType="org.sonar.db.alm.setting.ProjectAlmSettingDto">
+ <include refid="selectByAlmSql"/>
+ and p.project_uuid in
+ <foreach collection="projectUuids" open="(" close=")" item="projectUuid" separator=",">
+ #{projectUuid, jdbcType=VARCHAR}
+ </foreach>
</select>
<insert id="insert" parameterType="Map" useGeneratedKeys="false">
return resourcesUuid.stream().collect(toMap(identity(), any -> false));
}
+ @Override
+ public Map<String, Boolean> getProjectUuidToManaged(DbSession dbSession, Set<String> projectUuids) {
+ return findManagedProjectService()
+ .map(managedProjectService -> managedProjectService.getProjectUuidToManaged(dbSession, projectUuids))
+ .orElse(returnNonManagedForAll(projectUuids));
+ }
+
@Override
public boolean isProjectManaged(DbSession dbSession, String projectUuid) {
return findManagedProjectService()
*/
package org.sonar.server.management;
+import java.util.Map;
+import java.util.Set;
import org.sonar.db.DbSession;
public interface ManagedProjectService {
+ Map<String, Boolean> getProjectUuidToManaged(DbSession dbSession, Set<String> projectUuids);
+
boolean isProjectManaged(DbSession dbSession, String projectUuid);
}
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
@RunWith(MockitoJUnitRunner.class)
public class DelegatingManagedServicesTest {
return anotherManagedInstanceService;
}
+ @Test
+ public void getProjectUuidToManaged_whenNoDelegates_setAllProjectsAsNonManaged() {
+ Set<String> projectUuids = Set.of("a", "b");
+ DelegatingManagedServices managedInstanceService = NO_MANAGED_SERVICES;
+
+ Map<String, Boolean> projectUuidToManaged = managedInstanceService.getProjectUuidToManaged(dbSession, projectUuids);
+
+ assertThat(projectUuidToManaged).containsExactlyInAnyOrderEntriesOf(Map.of("a", false, "b", false));
+ }
+
+ @Test
+ public void getProjectUuidToManaged_delegatesToRightService_andPropagateAnswer() {
+ Set<String> projectUuids = Set.of("a", "b");
+ Map<String, Boolean> serviceResponse = Map.of("a", false, "b", true);
+
+ ManagedInstanceService anotherManagedProjectService = getManagedProjectService(projectUuids, serviceResponse);
+ DelegatingManagedServices managedInstanceService = new DelegatingManagedServices(Set.of(new NeverManagedInstanceService(), anotherManagedProjectService));
+
+ Map<String, Boolean> projectUuidToManaged = managedInstanceService.getProjectUuidToManaged(dbSession, projectUuids);
+
+ assertThat(projectUuidToManaged).containsExactlyInAnyOrderEntriesOf(serviceResponse);
+ }
+
+ private ManagedInstanceService getManagedProjectService(Set<String> projectUuids, Map<String, Boolean> uuidsToManaged) {
+ ManagedInstanceService anotherManagedProjectService = mock(ManagedInstanceService.class, withSettings().extraInterfaces(ManagedProjectService.class));
+ when(anotherManagedProjectService.isInstanceExternallyManaged()).thenReturn(true);
+ doReturn(uuidsToManaged).when((ManagedProjectService) anotherManagedProjectService).getProjectUuidToManaged(dbSession, projectUuids);
+ return anotherManagedProjectService;
+ }
+
@Test
public void isProjectManaged_whenManagedInstanceServices_shouldDelegatesToRightService() {
DelegatingManagedServices managedInstanceService = new DelegatingManagedServices(Set.of(new NeverManagedInstanceService(), new AlwaysManagedInstanceService()));
return false;
}
+ @Override
+ public Map<String, Boolean> getProjectUuidToManaged(DbSession dbSession, Set<String> projectUuids) {
+ return null;
+ }
+
@Override
public boolean isProjectManaged(DbSession dbSession, String projectUuid) {
return false;
return true;
}
+ @Override
+ public Map<String, Boolean> getProjectUuidToManaged(DbSession dbSession, Set<String> projectUuids) {
+ return null;
+ }
+
@Override
public boolean isProjectManaged(DbSession dbSession, String projectUuid) {
return true;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.component.ProjectData;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.management.ManagedProjectService;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.sonar.api.server.ws.WebService.Param.PAGE;
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
@Rule
public final DbTester db = DbTester.create();
- private final WsActionTester ws = new WsActionTester(new SearchAction(db.getDbClient(), userSession));
+ private final ManagedProjectService managedProjectService = mock(ManagedProjectService.class);
+
+ private final WsActionTester ws = new WsActionTester(new SearchAction(db.getDbClient(), userSession, managedProjectService));
@Test
public void search_by_key_query_with_partial_match_case_insensitive() {
assertThat(result.getComponentsList()).isEmpty();
}
+ @Test
+ public void search_return_manage_status() {
+ userSession.addPermission(ADMINISTER);
+ ProjectData managedProject = db.components().insertPrivateProject();
+ ProjectData notManagedProject = db.components().insertPrivateProject();
+
+ when(managedProjectService.getProjectUuidToManaged(any(), eq(Set.of(managedProject.projectUuid(), notManagedProject.projectUuid()))))
+ .thenReturn(Map.of(
+ managedProject.projectUuid(), true,
+ notManagedProject.projectUuid(), false
+ ));
+
+ SearchWsResponse result = call(SearchRequest.builder().build());
+ assertThat(result.getComponentsList())
+ .extracting(Component::getKey, Component::getManaged)
+ .containsExactlyInAnyOrder(
+ tuple(managedProject.projectKey(), true),
+ tuple(notManagedProject.projectKey(), false));
+ }
+
private static String toStringAtUTC(Date d) {
OffsetDateTime offsetTime = d.toInstant().atOffset(ZoneOffset.UTC);
return DateUtils.formatDateTime(offsetTime);
public void json_example() {
userSession.addPermission(ADMINISTER);
ProjectData publicProject = db.components().insertPublicProject("project-uuid-1", p -> p.setName("Project Name 1").setKey("project-key-1").setPrivate(false));
- ProjectData privateProject = db.components().insertPrivateProject("project-uuid-2", p -> p.setName("Project Name 1").setKey("project-key-2"));
+ ProjectData privateProject = db.components().insertPrivateProject("project-uuid-2", p -> p.setName("Project Name 2").setKey("project-key-2"));
db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(publicProject.getMainBranchDto())
.setCreatedAt(parseDateTime("2017-03-01T11:39:03+0300").getTime())
.setRevision("cfb82f55c6ef32e61828c4cb3db2da12795fd767"));
import org.sonar.db.component.ProjectLastAnalysisDateDto;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.permission.GlobalPermission;
+import org.sonar.server.management.ManagedProjectService;
import org.sonar.server.project.Visibility;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Projects.SearchWsResponse;
import static java.util.Optional.ofNullable;
import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
import static org.sonar.api.resources.Qualifiers.APP;
import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.VIEW;
private final DbClient dbClient;
private final UserSession userSession;
+ private final ManagedProjectService managedProjectService;
- public SearchAction(DbClient dbClient, UserSession userSession) {
+ public SearchAction(DbClient dbClient, UserSession userSession, ManagedProjectService managedProjectService) {
this.dbClient = dbClient;
this.userSession = userSession;
+ this.managedProjectService = managedProjectService;
}
@Override
"Requires 'Administer System' permission")
.addPagingParams(100, MAX_PAGE_SIZE)
.setResponseExample(getClass().getResource("search-example.json"))
+ .setChangelog(new Change("10.2", "Response includes 'managed' field."))
.setChangelog(new Change("9.1", "The parameter '" + PARAM_ANALYZED_BEFORE + "' and the field 'lastAnalysisDate' of the returned projects "
+ "take into account the analysis of all branches and pull requests, not only the main branch."))
.setHandler(this);
List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, query, paging.offset(), paging.pageSize());
Set<String> componentUuids = components.stream().map(ComponentDto::uuid).collect(Collectors.toSet());
List<BranchDto> branchDtos = dbClient.branchDao().selectByUuids(dbSession, componentUuids);
- Map<String, String> projectUuidByComponentUuid = branchDtos.stream().collect(Collectors.toMap(BranchDto::getUuid,BranchDto::getProjectUuid));
- Map<String, Long> lastAnalysisDateByComponentUuid = dbClient.snapshotDao().selectLastAnalysisDateByProjectUuids(dbSession, projectUuidByComponentUuid.values()).stream()
+ Map<String, String> componentUuidToProjectUuid = branchDtos.stream().collect(Collectors.toMap(BranchDto::getUuid,BranchDto::getProjectUuid));
+ Map<String, Boolean> projectUuidToManaged = managedProjectService.getProjectUuidToManaged(dbSession, new HashSet<>(componentUuidToProjectUuid.values()));
+ Map<String, Boolean> componentUuidToManaged = toComponentUuidToManaged(componentUuidToProjectUuid, projectUuidToManaged);
+ Map<String, Long> lastAnalysisDateByComponentUuid = dbClient.snapshotDao().selectLastAnalysisDateByProjectUuids(dbSession, componentUuidToProjectUuid.values()).stream()
.collect(Collectors.toMap(ProjectLastAnalysisDateDto::getProjectUuid, ProjectLastAnalysisDateDto::getDate));
Map<String, SnapshotDto> snapshotsByComponentUuid = dbClient.snapshotDao()
.selectLastAnalysesByRootComponentUuids(dbSession, componentUuids).stream()
.collect(Collectors.toMap(SnapshotDto::getRootComponentUuid, identity()));
- return buildResponse(components, snapshotsByComponentUuid, lastAnalysisDateByComponentUuid, projectUuidByComponentUuid, paging);
+ return buildResponse(components, snapshotsByComponentUuid, lastAnalysisDateByComponentUuid, componentUuidToProjectUuid, componentUuidToManaged, paging);
}
}
+ private Map<String, Boolean> toComponentUuidToManaged(Map<String, String> componentUuidToProjectUuid, Map<String, Boolean> projectUuidToManaged) {
+ return componentUuidToProjectUuid.keySet().stream()
+ .collect(toMap(identity(), componentUuid -> isComponentManaged(
+ componentUuidToProjectUuid.get(componentUuid),
+ projectUuidToManaged))
+ );
+ }
+
+ private boolean isComponentManaged(String projectUuid, Map<String, Boolean> projectUuidToManaged) {
+ return ofNullable(projectUuidToManaged.get(projectUuid)).orElse(false);
+ }
+
static ComponentQuery buildDbQuery(SearchRequest request) {
List<String> qualifiers = request.getQualifiers();
ComponentQuery.Builder query = ComponentQuery.builder()
}
private static SearchWsResponse buildResponse(List<ComponentDto> components, Map<String, SnapshotDto> snapshotsByComponentUuid,
- Map<String, Long> lastAnalysisDateByComponentUuid, Map<String, String> projectUuidByComponentUuid, Paging paging) {
+ Map<String, Long> lastAnalysisDateByComponentUuid, Map<String, String> projectUuidByComponentUuid, Map<String, Boolean> componentUuidToManaged, Paging paging) {
SearchWsResponse.Builder responseBuilder = newBuilder();
responseBuilder.getPagingBuilder()
.setPageIndex(paging.pageIndex())
.build();
components.stream()
- .map(dto -> dtoToProject(dto, snapshotsByComponentUuid.get(dto.uuid()), lastAnalysisDateByComponentUuid.get(projectUuidByComponentUuid.get(dto.uuid()))))
+ .map(dto -> dtoToProject(dto, snapshotsByComponentUuid.get(dto.uuid()), lastAnalysisDateByComponentUuid.get(projectUuidByComponentUuid.get(dto.uuid())),
+ PROJECT.equals(dto.qualifier()) ? componentUuidToManaged.get(dto.uuid()) : null))
.forEach(responseBuilder::addComponents);
return responseBuilder.build();
}
- private static Component dtoToProject(ComponentDto dto, @Nullable SnapshotDto snapshot, @Nullable Long lastAnalysisDate) {
+ private static Component dtoToProject(ComponentDto dto, @Nullable SnapshotDto snapshot, @Nullable Long lastAnalysisDate, @Nullable Boolean isManaged) {
Component.Builder builder = Component.newBuilder()
.setKey(dto.getKey())
.setName(dto.name())
ofNullable(lastAnalysisDate).ifPresent(d -> builder.setLastAnalysisDate(formatDateTime(d)));
ofNullable(snapshot.getRevision()).ifPresent(builder::setRevision);
}
+ ofNullable(isManaged).ifPresent(builder::setManaged);
return builder.build();
}
"qualifier": "TRK",
"visibility": "public",
"lastAnalysisDate": "2017-03-01T11:39:03+0300",
- "revision": "cfb82f55c6ef32e61828c4cb3db2da12795fd767"
+ "revision": "cfb82f55c6ef32e61828c4cb3db2da12795fd767",
+ "managed": false
},
{
"key": "project-key-2",
- "name": "Project Name 1",
+ "name": "Project Name 2",
"qualifier": "TRK",
"visibility": "private",
"lastAnalysisDate": "2017-03-02T15:21:47+0300",
- "revision": "7be96a94ac0c95a61ee6ee0ef9c6f808d386a355"
+ "revision": "7be96a94ac0c95a61ee6ee0ef9c6f808d386a355",
+ "managed": false
}
]
}
optional string visibility = 6;
optional string lastAnalysisDate = 7;
optional string revision = 8;
+ optional bool managed = 9;
}
}