public class ProjectQgateAssociationDto {
private Long id;
+ private String key;
private String name;
private String gateId;
return this;
}
+ public String getKey() {
+ return key;
+ }
+
+ public ProjectQgateAssociationDto setKey(String key) {
+ this.key = key;
+ return this;
+ }
+
public String getName() {
return name;
}
return this;
}
- public ProjectQgateAssociation toQgateAssociation() {
- return new ProjectQgateAssociation()
- .setId(id)
- .setName(name)
- .setMember(gateId != null);
- }
}
<mapper namespace="org.sonar.db.qualitygate.ProjectQgateAssociationMapper">
<select id="selectProjects" parameterType="map" resultType="ProjectQgateAssociation">
- SELECT proj.id as id, proj.name as name, prop.text_value as gateId
+ SELECT proj.id as id, proj.kee as key, proj.name as name, prop.text_value as gateId
FROM projects proj
LEFT JOIN properties prop ON prop.resource_id=proj.id AND prop.prop_key='sonar.qualitygate' AND prop.text_value = #{query.gateId}
where
.build());
assertThat(result)
- .extracting(ProjectQgateAssociationDto::getId, ProjectQgateAssociationDto::getName, ProjectQgateAssociationDto::getGateId)
+ .extracting(ProjectQgateAssociationDto::getId, ProjectQgateAssociationDto::getKey, ProjectQgateAssociationDto::getName, ProjectQgateAssociationDto::getGateId)
.containsExactlyInAnyOrder(
- tuple(project1.getId(), project1.name(), qualityGate1.getId().toString()),
- tuple(project2.getId(), project2.name(), qualityGate1.getId().toString()),
- tuple(project3.getId(), project3.name(), null));
+ tuple(project1.getId(), project1.getKey(), project1.name(), qualityGate1.getId().toString()),
+ tuple(project2.getId(), project2.getKey(), project2.name(), qualityGate1.getId().toString()),
+ tuple(project3.getId(), project3.getKey(), project3.name(), null));
}
@Test
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.db.qualitygate;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ProjectQgateAssociationDtoTest {
-
- @Test
- public void to_assoc_with_project_having_assoc() {
- ProjectQgateAssociation project = new ProjectQgateAssociationDto()
- .setId(1L)
- .setName("polop")
- .setGateId("10")
- .toQgateAssociation();
-
- assertThat(project.id()).isEqualTo(1);
- assertThat(project.name()).isEqualTo("polop");
- assertThat(project.isMember()).isTrue();
- }
-
- @Test
- public void to_assoc_with_project_not_having_assoc() {
- ProjectQgateAssociation project = new ProjectQgateAssociationDto()
- .setId(1L)
- .setName("polop")
- .setGateId(null)
- .toQgateAssociation();
-
- assertThat(project.id()).isEqualTo(1);
- assertThat(project.name()).isEqualTo("polop");
- assertThat(project.isMember()).isFalse();
- }
-
-}
import com.google.common.io.Resources;
import java.util.Collection;
import java.util.List;
+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.organization.OrganizationDto;
-import org.sonar.db.qualitygate.ProjectQgateAssociation;
import org.sonar.db.qualitygate.ProjectQgateAssociationDto;
import org.sonar.db.qualitygate.ProjectQgateAssociationQuery;
import org.sonar.db.qualitygate.QGateWithOrgDto;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Qualitygates;
+import static java.util.stream.Collectors.toList;
import static org.sonar.api.server.ws.WebService.Param.SELECTED;
import static org.sonar.api.utils.Paging.forPageIndex;
import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.ANY;
"Only authorized projects for current user will be returned.")
.setSince("4.3")
.setResponseExample(Resources.getResource(this.getClass(), "search-example.json"))
+ .setChangelog(
+ new Change("7.9", "New field 'paging' in response"),
+ new Change("7.9", "New field 'key' returning the project key in 'results' response"),
+ new Change("7.9", "Field 'more' is deprecated in the response"))
.setHandler(this);
action.createParam(PARAM_GATE_ID)
OrganizationDto organization = wsSupport.getOrganization(dbSession, request);
QGateWithOrgDto qualityGate = wsSupport.getByOrganizationAndId(dbSession, organization, request.mandatoryParamAsLong(PARAM_GATE_ID));
- Association associations = find(dbSession,
- ProjectQgateAssociationQuery.builder()
- .qualityGate(qualityGate)
- .membership(request.param(PARAM_QUERY) == null ? request.param(SELECTED) : ANY)
- .projectSearch(request.param(PARAM_QUERY))
- .pageIndex(request.paramAsInt(PARAM_PAGE))
- .pageSize(request.paramAsInt(PARAM_PAGE_SIZE))
- .build());
-
- Qualitygates.SearchResponse.Builder createResponse = Qualitygates.SearchResponse.newBuilder()
- .setMore(associations.hasMoreResults());
-
- for (ProjectQgateAssociation project : associations.projects()) {
+
+ ProjectQgateAssociationQuery projectQgateAssociationQuery = ProjectQgateAssociationQuery.builder()
+ .qualityGate(qualityGate)
+ .membership(request.param(PARAM_QUERY) == null ? request.param(SELECTED) : ANY)
+ .projectSearch(request.param(PARAM_QUERY))
+ .pageIndex(request.paramAsInt(PARAM_PAGE))
+ .pageSize(request.paramAsInt(PARAM_PAGE_SIZE))
+ .build();
+ List<ProjectQgateAssociationDto> projects = dbClient.projectQgateAssociationDao().selectProjects(dbSession, projectQgateAssociationQuery);
+ List<ProjectQgateAssociationDto> authorizedProjects = keepAuthorizedProjects(dbSession, projects);
+ Paging paging = forPageIndex(projectQgateAssociationQuery.pageIndex())
+ .withPageSize(projectQgateAssociationQuery.pageSize())
+ .andTotal(authorizedProjects.size());
+ List<ProjectQgateAssociationDto> paginatedProjects = getPaginatedProjects(authorizedProjects, paging);
+
+ Qualitygates.SearchResponse.Builder createResponse = Qualitygates.SearchResponse.newBuilder().setMore(paging.hasNextPage());
+ createResponse.getPagingBuilder()
+ .setPageIndex(paging.pageIndex())
+ .setPageSize(paging.pageSize())
+ .setTotal(paging.total())
+ .build();
+
+ for (ProjectQgateAssociationDto project : paginatedProjects) {
createResponse.addResultsBuilder()
- .setId(project.id())
- .setName(project.name())
- .setSelected(project.isMember());
+ .setId(project.getId())
+ .setName(project.getName())
+ .setKey(project.getKey())
+ .setSelected(project.getGateId() != null);
}
writeProtobuf(createResponse.build(), request, response);
}
}
- private SearchAction.Association find(DbSession dbSession, ProjectQgateAssociationQuery query) {
- List<ProjectQgateAssociationDto> projects = dbClient.projectQgateAssociationDao().selectProjects(dbSession, query);
- List<ProjectQgateAssociationDto> authorizedProjects = keepAuthorizedProjects(dbSession, projects);
-
- Paging paging = forPageIndex(query.pageIndex())
- .withPageSize(query.pageSize())
- .andTotal(authorizedProjects.size());
- return new SearchAction.Association(toProjectAssociations(getPaginatedProjects(authorizedProjects, paging)), paging.hasNextPage());
- }
-
private static List<ProjectQgateAssociationDto> getPaginatedProjects(List<ProjectQgateAssociationDto> projects, Paging paging) {
- return projects.stream().skip(paging.offset()).limit(paging.pageSize()).collect(MoreCollectors.toList());
- }
-
- private static List<ProjectQgateAssociation> toProjectAssociations(List<ProjectQgateAssociationDto> dtos) {
- return dtos.stream().map(ProjectQgateAssociationDto::toQgateAssociation).collect(MoreCollectors.toList());
+ return projects.stream().skip(paging.offset()).limit(paging.pageSize()).collect(toList());
}
private List<ProjectQgateAssociationDto> keepAuthorizedProjects(DbSession dbSession, List<ProjectQgateAssociationDto> projects) {
Collection<Long> authorizedProjectIds = dbClient.authorizationDao().keepAuthorizedProjectIds(dbSession, projectIds, userSession.getUserId(), UserRole.USER);
return projects.stream().filter(project -> authorizedProjectIds.contains(project.getId())).collect(MoreCollectors.toList());
}
-
- private static class Association {
- private List<ProjectQgateAssociation> projects;
- private boolean hasMoreResults;
-
- private Association(List<ProjectQgateAssociation> projects, boolean hasMoreResults) {
- this.projects = projects;
- this.hasMoreResults = hasMoreResults;
- }
-
- public List<ProjectQgateAssociation> projects() {
- return projects;
- }
-
- public boolean hasMoreResults() {
- return hasMoreResults;
- }
- }
}
{
- "more": true,
+ "paging": {
+ "pageIndex": 1,
+ "pageSize": 100,
+ "total": 2
+ },
"results": [
{
"id": 1,
"name": "Simple Java project analyzed with the SonarQube Runner",
+ "key": "somple-java",
"selected": true
},
{
"id": 4,
"name": "My Project",
- "selected": true
+ "key": "my-project",
+ "selected": false
}
]
}
new QualityGatesWsSupport(dbClient, userSession, defaultOrganizationProvider));
private WsActionTester ws = new WsActionTester(underTest);
- @Test
- public void definition() {
- WebService.Action action = ws.getDef();
-
- assertThat(action).isNotNull();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.isPost()).isFalse();
- assertThat(action.responseExampleAsString()).isNotEmpty();
- assertThat(action.params())
- .extracting(WebService.Param::key, WebService.Param::isRequired)
- .containsExactlyInAnyOrder(
- tuple("gateId", true),
- tuple("query", false),
- tuple("organization", false),
- tuple("selected", false),
- tuple("page", false),
- tuple("pageSize", false));
- }
-
@Test
public void search_projects_of_a_quality_gate_from_an_organization() {
OrganizationDto organization = db.organizations().insert();
.executeProtobuf(SearchResponse.class);
assertThat(response.getResultsList())
- .extracting(Result::getId, Result::getName)
- .containsExactlyInAnyOrder(tuple(project.getId(), project.name()));
- assertThat(response.getMore()).isFalse();
+ .extracting(Result::getId, Result::getKey, Result::getName)
+ .containsExactlyInAnyOrder(tuple(project.getId(), project.getKey(), project.name()));
}
@Test
assertThat(response.getResultsList())
.extracting(Result::getId, Result::getName)
.containsExactlyInAnyOrder(tuple(project.getId(), project.name()));
- assertThat(response.getMore()).isFalse();
}
@Test
.executeProtobuf(SearchResponse.class);
assertThat(response.getResultsList())
- .extracting(Result::getName, Result::getSelected)
+ .extracting(Result::getName, Result::getKey, Result::getSelected)
.containsExactlyInAnyOrder(
- tuple(associatedProject.name(), true),
- tuple(unassociatedProject.name(), false));
+ tuple(associatedProject.name(), associatedProject.getKey(), true),
+ tuple(unassociatedProject.name(), unassociatedProject.getKey(), false));
}
@Test
}
@Test
- public void more_is_true_when_not_all_project_fit_in_page_size() {
+ public void test_pagination_on_many_pages() {
OrganizationDto organization = db.organizations().insert();
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization);
for (int i = 0; i < 20; i++) {
ComponentDto project = db.components().insertPublicProject(organization);
db.qualityGates().associateProjectToQualityGate(project, qualityGate);
}
+ userSession.addPermission(ADMINISTER_QUALITY_GATES, organization);
+
+ SearchResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId()))
+ .setParam(PARAM_ORGANIZATION, organization.getKey())
+ .setParam(PARAM_PAGE_SIZE, valueOf(5))
+ .setParam(PARAM_PAGE, valueOf(2))
+ .executeProtobuf(SearchResponse.class);
+ assertThat(response)
+ .extracting(SearchResponse::getMore,
+ searchResponse -> searchResponse.getPaging().getPageIndex(),
+ searchResponse -> searchResponse.getPaging().getPageSize(),
+ searchResponse -> searchResponse.getPaging().getTotal())
+ .contains(true, 2, 5, 20);
+ }
+
+ @Test
+ public void test_pagination_on_one_page() {
+ OrganizationDto organization = db.organizations().insert();
+ QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization);
+ for (int i = 0; i < 20; i++) {
+ ComponentDto project = db.components().insertPublicProject(organization);
+ db.qualityGates().associateProjectToQualityGate(project, qualityGate);
+ }
userSession.addPermission(ADMINISTER_QUALITY_GATES, organization);
SearchResponse response = ws.newRequest()
.setParam(PARAM_GATE_ID, valueOf(qualityGate.getId()))
.setParam(PARAM_ORGANIZATION, organization.getKey())
- .setParam(PARAM_PAGE_SIZE, valueOf(10))
+ .setParam(PARAM_PAGE_SIZE, valueOf(100))
.setParam(PARAM_PAGE, valueOf(1))
.executeProtobuf(SearchResponse.class);
- assertThat(response.getMore()).isTrue();
- assertThat(response.getResultsCount()).isEqualTo(10);
+ assertThat(response)
+ .extracting(SearchResponse::getMore,
+ searchResponse -> searchResponse.getPaging().getPageIndex(),
+ searchResponse -> searchResponse.getPaging().getPageSize(),
+ searchResponse -> searchResponse.getPaging().getTotal())
+ .contains(false, 1, 100, 20);
}
@Test
.executeProtobuf(SearchResponse.class);
}
+ @Test
+ public void definition() {
+ WebService.Action action = ws.getDef();
+
+ assertThat(action).isNotNull();
+ assertThat(action.isInternal()).isFalse();
+ assertThat(action.isPost()).isFalse();
+ assertThat(action.responseExampleAsString()).isNotEmpty();
+ assertThat(action.params())
+ .extracting(WebService.Param::key, WebService.Param::isRequired)
+ .containsExactlyInAnyOrder(
+ tuple("gateId", true),
+ tuple("query", false),
+ tuple("organization", false),
+ tuple("selected", false),
+ tuple("page", false),
+ tuple("pageSize", false));
+ }
+
}
package sonarqube.ws.qualitygate;
+import "ws-commons.proto";
+
option java_package = "org.sonarqube.ws";
option java_outer_classname = "Qualitygates";
option optimize_for = SPEED;
// GET api/qualitygates/search
message SearchResponse {
+ // Deprecated since 7.9
optional bool more = 1;
repeated Result results = 2;
+ optional sonarqube.ws.commons.Paging paging = 3;
message Result {
optional int64 id = 1;
optional string name = 2;
optional bool selected = 3;
+ optional string key = 4;
}
}