@@ -34,6 +34,7 @@ public class ProjectsWsModule extends Module { | |||
GhostsAction.class, | |||
ProvisionedAction.class, | |||
SearchMyProjectsAction.class, | |||
SearchMyProjectsDataLoader.class); | |||
SearchMyProjectsDataLoader.class, | |||
SearchAction.class); | |||
} | |||
} |
@@ -0,0 +1,153 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 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.project.ws; | |||
import java.util.List; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.server.ws.WebService.Param; | |||
import org.sonar.api.utils.Paging; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentQuery; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.WsProjects.SearchWsResponse; | |||
import org.sonarqube.ws.client.project.SearchWsRequest; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.util.Optional.ofNullable; | |||
import static org.sonar.api.resources.Qualifiers.PROJECT; | |||
import static org.sonar.api.resources.Qualifiers.VIEW; | |||
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.WsProjects.SearchWsResponse.Component; | |||
import static org.sonarqube.ws.WsProjects.SearchWsResponse.newBuilder; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_SEARCH; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS; | |||
public class SearchAction implements ProjectsWsAction { | |||
private final DbClient dbClient; | |||
private final UserSession userSession; | |||
private final DefaultOrganizationProvider defaultOrganizationProvider; | |||
private final ProjectsWsSupport support; | |||
public SearchAction(DbClient dbClient, UserSession userSession, DefaultOrganizationProvider defaultOrganizationProvider, ProjectsWsSupport support) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.defaultOrganizationProvider = defaultOrganizationProvider; | |||
this.support = support; | |||
} | |||
@Override | |||
public void define(WebService.NewController context) { | |||
WebService.NewAction action = context.createAction(ACTION_SEARCH) | |||
.setSince("6.3") | |||
.setDescription("Search for projects or views.<br>" + | |||
"Requires 'System Administrator' permission") | |||
.setInternal(true) | |||
.addPagingParams(100) | |||
.addSearchQuery("sona", "component names", "component keys") | |||
.setResponseExample(getClass().getResource("search-example.json")) | |||
.setHandler(this); | |||
action.createParam(PARAM_QUALIFIERS) | |||
.setDescription("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers") | |||
.setPossibleValues(PROJECT, VIEW) | |||
.setDefaultValue(PROJECT); | |||
support.addOrganizationParam(action); | |||
} | |||
@Override | |||
public void handle(Request wsRequest, Response wsResponse) throws Exception { | |||
SearchWsResponse searchWsResponse = doHandle(toSearchWsRequest(wsRequest)); | |||
writeProtobuf(searchWsResponse, wsRequest, wsResponse); | |||
} | |||
private static SearchWsRequest toSearchWsRequest(Request request) { | |||
return SearchWsRequest.builder() | |||
.setOrganization(request.param(PARAM_ORGANIZATION)) | |||
.setQualifiers(request.mandatoryParamAsStrings(PARAM_QUALIFIERS)) | |||
.setQuery(request.param(Param.TEXT_QUERY)) | |||
.setPage(request.mandatoryParamAsInt(Param.PAGE)) | |||
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)).build(); | |||
} | |||
private SearchWsResponse doHandle(SearchWsRequest request) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
OrganizationDto organization = support.getOrganization(dbSession, ofNullable(request.getOrganization()).orElseGet(defaultOrganizationProvider.get()::getKey)); | |||
userSession.checkOrganizationPermission(organization.getUuid(), SYSTEM_ADMIN); | |||
ComponentQuery query = buildQuery(request); | |||
Paging paging = buildPaging(dbSession, request, organization, query); | |||
List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), query, paging.offset(), paging.pageSize()); | |||
return buildResponse(components, organization, paging); | |||
} | |||
} | |||
private static ComponentQuery buildQuery(SearchWsRequest request) { | |||
List<String> qualifiers = request.getQualifiers(); | |||
return ComponentQuery.builder() | |||
.setNameOrKeyQuery(request.getQuery()) | |||
.setQualifiers(qualifiers.toArray(new String[qualifiers.size()])) | |||
.build(); | |||
} | |||
private Paging buildPaging(DbSession dbSession, SearchWsRequest request, OrganizationDto organization, ComponentQuery query) { | |||
int total = dbClient.componentDao().countByQuery(dbSession, organization.getUuid(), query); | |||
return Paging.forPageIndex(request.getPage()) | |||
.withPageSize(request.getPageSize()) | |||
.andTotal(total); | |||
} | |||
private static SearchWsResponse buildResponse(List<ComponentDto> components, OrganizationDto organization, Paging paging) { | |||
SearchWsResponse.Builder responseBuilder = newBuilder(); | |||
responseBuilder.getPagingBuilder() | |||
.setPageIndex(paging.pageIndex()) | |||
.setPageSize(paging.pageSize()) | |||
.setTotal(paging.total()) | |||
.build(); | |||
components.stream() | |||
.map(dto -> dtoToProject(organization, dto)) | |||
.forEach(responseBuilder::addComponents); | |||
return responseBuilder.build(); | |||
} | |||
private static Component dtoToProject(OrganizationDto organization, ComponentDto dto) { | |||
checkArgument( | |||
organization.getUuid().equals(dto.getOrganizationUuid()), | |||
"No Organization found for uuid '%s'", | |||
dto.getOrganizationUuid()); | |||
Component.Builder builder = Component.newBuilder() | |||
.setOrganization(organization.getKey()) | |||
.setId(dto.uuid()) | |||
.setKey(dto.key()) | |||
.setName(dto.name()) | |||
.setQualifier(dto.qualifier()); | |||
return builder.build(); | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
{ | |||
"paging": { | |||
"pageIndex": 1, | |||
"pageSize": 100, | |||
"total": 2 | |||
}, | |||
"components": [ | |||
{ | |||
"organization": "my-org-1", | |||
"id": "project-uuid-1", | |||
"key": "project-key-1", | |||
"name": "Project Name 1", | |||
"qualifier": "TRK" | |||
}, | |||
{ | |||
"organization": "my-org-1", | |||
"id": "project-uuid-2", | |||
"key": "project-key-2", | |||
"name": "Project Name 1", | |||
"qualifier": "TRK" | |||
} | |||
] | |||
} |
@@ -30,6 +30,6 @@ public class ProjectsWsModuleTest { | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new ProjectsWsModule().configure(container); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 10); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 11); | |||
} | |||
} |
@@ -0,0 +1,292 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 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.project.ws; | |||
import com.google.common.base.Joiner; | |||
import com.google.common.base.Throwables; | |||
import java.io.IOException; | |||
import java.net.URISyntaxException; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.assertj.core.api.Assertions; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.organization.TestDefaultOrganizationProvider; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.MediaTypes; | |||
import org.sonarqube.ws.WsProjects.SearchWsResponse; | |||
import org.sonarqube.ws.WsProjects.SearchWsResponse.Component; | |||
import org.sonarqube.ws.client.component.ComponentsWsParameters; | |||
import org.sonarqube.ws.client.project.SearchWsRequest; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
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; | |||
import static org.sonar.core.permission.GlobalPermissions.QUALITY_PROFILE_ADMIN; | |||
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; | |||
import static org.sonar.core.util.Protobuf.setNullable; | |||
import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newProjectDto; | |||
import static org.sonar.db.component.ComponentTesting.newView; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonarqube.ws.MediaTypes.PROTOBUF; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS; | |||
public class SearchActionTest { | |||
private static final String PROJECT_KEY_1 = "project1"; | |||
private static final String PROJECT_KEY_2 = "project2"; | |||
private static final String PROJECT_KEY_3 = "project3"; | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
public DbTester db = DbTester.create(); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); | |||
private WsActionTester ws = new WsActionTester(new SearchAction(db.getDbClient(), userSession, defaultOrganizationProvider, new ProjectsWsSupport(db.getDbClient()))); | |||
@Test | |||
public void search_by_key_query() throws IOException { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), SYSTEM_ADMIN); | |||
db.components().insertComponents( | |||
newProjectDto(db.getDefaultOrganization()).setKey("project-_%-key"), | |||
newProjectDto(db.getDefaultOrganization()).setKey("project-key-without-escaped-characters")); | |||
SearchWsResponse response = call(SearchWsRequest.builder().setQuery("project-_%-key").build()); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly("project-_%-key"); | |||
} | |||
@Test | |||
public void search_projects_when_no_qualifier_set() throws IOException { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), SYSTEM_ADMIN); | |||
db.components().insertComponents( | |||
newProjectDto(db.getDefaultOrganization()).setKey(PROJECT_KEY_1), | |||
newView(db.getDefaultOrganization())); | |||
SearchWsResponse response = call(SearchWsRequest.builder().build()); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(PROJECT_KEY_1); | |||
} | |||
@Test | |||
public void search_projects() throws IOException { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), SYSTEM_ADMIN); | |||
ComponentDto project = newProjectDto(db.getDefaultOrganization()).setKey(PROJECT_KEY_1); | |||
ComponentDto module = newModuleDto(project); | |||
ComponentDto directory = newDirectory(module, "dir"); | |||
ComponentDto file = newFileDto(directory); | |||
db.components().insertComponents( | |||
project, module, directory, file, | |||
newProjectDto(db.getDefaultOrganization()).setKey(PROJECT_KEY_2), | |||
newView(db.getDefaultOrganization())); | |||
SearchWsResponse response = call(SearchWsRequest.builder().setQualifiers(singletonList("TRK")).build()); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(PROJECT_KEY_1, PROJECT_KEY_2); | |||
} | |||
@Test | |||
public void search_views() throws IOException { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), SYSTEM_ADMIN); | |||
db.components().insertComponents( | |||
newProjectDto(db.getDefaultOrganization()).setKey(PROJECT_KEY_1), | |||
newView(db.getDefaultOrganization()).setKey("view1")); | |||
SearchWsResponse response = call(SearchWsRequest.builder().setQualifiers(singletonList("VW")).build()); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly("view1"); | |||
} | |||
@Test | |||
public void search_projects_and_views() throws IOException { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), SYSTEM_ADMIN); | |||
db.components().insertComponents( | |||
newProjectDto(db.getDefaultOrganization()).setKey(PROJECT_KEY_1), | |||
newView(db.getDefaultOrganization()).setKey("view1")); | |||
SearchWsResponse response = call(SearchWsRequest.builder().setQualifiers(asList("TRK", "VW")).build()); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(PROJECT_KEY_1, "view1"); | |||
} | |||
@Test | |||
public void search_on_default_organization_when_no_organization_set() throws IOException { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), SYSTEM_ADMIN); | |||
OrganizationDto otherOrganization = db.organizations().insert(); | |||
db.components().insertComponents( | |||
newProjectDto(db.getDefaultOrganization()).setKey(PROJECT_KEY_1), | |||
newProjectDto(db.getDefaultOrganization()).setKey(PROJECT_KEY_2), | |||
newProjectDto(otherOrganization).setKey(PROJECT_KEY_3)); | |||
SearchWsResponse response = call(SearchWsRequest.builder().build()); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(PROJECT_KEY_1, PROJECT_KEY_2); | |||
} | |||
@Test | |||
public void search_for_projects_on_given_organization() throws IOException { | |||
OrganizationDto organization1 = db.organizations().insert(); | |||
OrganizationDto organization2 = db.organizations().insert(); | |||
userSession.addOrganizationPermission(organization1, SYSTEM_ADMIN); | |||
ComponentDto project1 = newProjectDto(organization1); | |||
ComponentDto project2 = newProjectDto(organization1); | |||
ComponentDto project3 = newProjectDto(organization2); | |||
db.components().insertComponents(project1, project2, project3); | |||
SearchWsResponse response = call(SearchWsRequest.builder().setOrganization(organization1.getKey()).build()); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(project1.key(), project2.key()); | |||
} | |||
@Test | |||
public void result_is_paginated() throws IOException { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), SYSTEM_ADMIN); | |||
List<ComponentDto> componentDtoList = new ArrayList<>(); | |||
for (int i = 1; i <= 9; i++) { | |||
componentDtoList.add(newProjectDto(db.getDefaultOrganization(), "project-uuid-" + i).setKey("project-key-" + i).setName("Project Name " + i)); | |||
} | |||
db.components().insertComponents(componentDtoList.toArray(new ComponentDto[] {})); | |||
SearchWsResponse response = call(SearchWsRequest.builder().setPage(2).setPageSize(3).build()); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsExactly("project-key-4", "project-key-5", "project-key-6"); | |||
} | |||
@Test | |||
public void fail_when_not_system_admin() throws Exception { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), QUALITY_PROFILE_ADMIN); | |||
expectedException.expect(ForbiddenException.class); | |||
call(SearchWsRequest.builder().build()); | |||
} | |||
@Test | |||
public void fail_on_unknown_organization() throws Exception { | |||
expectedException.expect(NotFoundException.class); | |||
call(SearchWsRequest.builder().setOrganization("unknown").build()); | |||
} | |||
@Test | |||
public void fail_on_invalid_qualifier() throws Exception { | |||
userSession.addOrganizationPermission(db.getDefaultOrganization(), QUALITY_PROFILE_ADMIN); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Value of parameter 'qualifiers' (BRC) must be one of: [TRK, VW]"); | |||
call(SearchWsRequest.builder().setQualifiers(singletonList("BRC")).build()); | |||
} | |||
@Test | |||
public void verify_define() { | |||
WebService.Action action = ws.getDef(); | |||
assertThat(action.key()).isEqualTo("search"); | |||
assertThat(action.isPost()).isFalse(); | |||
assertThat(action.description()).isEqualTo("Search for projects or views.<br>Requires 'System Administrator' permission"); | |||
assertThat(action.isInternal()).isTrue(); | |||
assertThat(action.since()).isEqualTo("6.3"); | |||
assertThat(action.handler()).isEqualTo(ws.getDef().handler()); | |||
assertThat(action.params()).hasSize(5); | |||
assertThat(action.responseExample()).isEqualTo(getClass().getResource("search-example.json")); | |||
WebService.Param organization = action.param("organization"); | |||
Assertions.assertThat(organization.description()).isEqualTo("The key of the organization"); | |||
Assertions.assertThat(organization.isInternal()).isTrue(); | |||
Assertions.assertThat(organization.isRequired()).isFalse(); | |||
Assertions.assertThat(organization.since()).isEqualTo("6.3"); | |||
WebService.Param qParam = action.param("q"); | |||
assertThat(qParam.isRequired()).isFalse(); | |||
assertThat(qParam.description()).isEqualTo("Limit search to component names or component keys that contain the supplied string."); | |||
WebService.Param qualifierParam = action.param("qualifiers"); | |||
assertThat(qualifierParam.isRequired()).isFalse(); | |||
assertThat(qualifierParam.description()).isEqualTo("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers"); | |||
assertThat(qualifierParam.possibleValues()).containsOnly("TRK", "VW"); | |||
assertThat(qualifierParam.defaultValue()).isEqualTo("TRK"); | |||
WebService.Param pParam = action.param("p"); | |||
assertThat(pParam.isRequired()).isFalse(); | |||
assertThat(pParam.defaultValue()).isEqualTo("1"); | |||
assertThat(pParam.description()).isEqualTo("1-based page number"); | |||
WebService.Param psParam = action.param("ps"); | |||
assertThat(psParam.isRequired()).isFalse(); | |||
assertThat(psParam.defaultValue()).isEqualTo("100"); | |||
assertThat(psParam.description()).isEqualTo("Page size. Must be greater than 0."); | |||
} | |||
@Test | |||
public void verify_response_example() throws URISyntaxException, IOException { | |||
OrganizationDto organizationDto = db.organizations().insertForKey("my-org-1"); | |||
userSession.addOrganizationPermission(organizationDto, SYSTEM_ADMIN); | |||
db.components().insertComponents( | |||
newProjectDto(organizationDto, "project-uuid-1").setName("Project Name 1").setKey("project-key-1"), | |||
newProjectDto(organizationDto, "project-uuid-2").setName("Project Name 1").setKey("project-key-2")); | |||
String response = ws.newRequest() | |||
.setMediaType(MediaTypes.JSON) | |||
.setParam(PARAM_ORGANIZATION, organizationDto.getKey()) | |||
.execute().getInput(); | |||
assertJson(response).isSimilarTo(ws.getDef().responseExampleAsString()); | |||
} | |||
private SearchWsResponse call(SearchWsRequest wsRequest) { | |||
TestRequest request = ws.newRequest() | |||
.setMediaType(PROTOBUF); | |||
setNullable(wsRequest.getOrganization(), organization -> request.setParam(PARAM_ORGANIZATION, organization)); | |||
List<String> qualifiers = wsRequest.getQualifiers(); | |||
if (!qualifiers.isEmpty()) { | |||
request.setParam(ComponentsWsParameters.PARAM_QUALIFIERS, Joiner.on(",").join(qualifiers)); | |||
} | |||
setNullable(wsRequest.getQuery(), query -> request.setParam(TEXT_QUERY, query)); | |||
setNullable(wsRequest.getPage(), page -> request.setParam(PAGE, String.valueOf(page))); | |||
setNullable(wsRequest.getPageSize(), pageSize -> request.setParam(PAGE_SIZE, String.valueOf(pageSize))); | |||
try { | |||
return SearchWsResponse.parseFrom(request.execute().getInputStream()); | |||
} catch (IOException e) { | |||
throw Throwables.propagate(e); | |||
} | |||
} | |||
} |
@@ -19,16 +19,23 @@ | |||
*/ | |||
package org.sonarqube.ws.client.project; | |||
import com.google.common.base.Joiner; | |||
import org.sonarqube.ws.WsProjects; | |||
import org.sonarqube.ws.WsProjects.CreateWsResponse; | |||
import org.sonarqube.ws.client.BaseService; | |||
import org.sonarqube.ws.client.GetRequest; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsConnector; | |||
import static org.sonar.api.server.ws.WebService.Param.*; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_CREATE; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_SEARCH; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.CONTROLLER; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS; | |||
/** | |||
* Maps web service {@code api/projects}. | |||
@@ -47,7 +54,7 @@ public class ProjectsService extends BaseService { | |||
*/ | |||
public CreateWsResponse create(CreateRequest project) { | |||
PostRequest request = new PostRequest(path(ACTION_CREATE)) | |||
.setParam("organization", project.getOrganization()) | |||
.setParam(PARAM_ORGANIZATION, project.getOrganization()) | |||
.setParam(PARAM_PROJECT, project.getKey()) | |||
.setParam(PARAM_NAME, project.getName()) | |||
.setParam(PARAM_BRANCH, project.getBranch()); | |||
@@ -62,4 +69,14 @@ public class ProjectsService extends BaseService { | |||
.setParam("id", request.getId()) | |||
.setParam("key", request.getKey())); | |||
} | |||
public WsProjects.SearchWsResponse search(SearchWsRequest request) { | |||
GetRequest get = new GetRequest(path(ACTION_SEARCH)) | |||
.setParam(PARAM_ORGANIZATION, request.getOrganization()) | |||
.setParam(PARAM_QUALIFIERS, Joiner.on(",").join(request.getQualifiers())) | |||
.setParam(TEXT_QUERY, request.getQuery()) | |||
.setParam(PAGE, request.getPage()) | |||
.setParam(PAGE_SIZE, request.getPageSize()); | |||
return call(get, WsProjects.SearchWsResponse.parser()); | |||
} | |||
} |
@@ -25,10 +25,13 @@ public class ProjectsWsParameters { | |||
public static final String ACTION_CREATE = "create"; | |||
public static final String ACTION_INDEX = "index"; | |||
public static final String ACTION_SEARCH = "search"; | |||
public static final String PARAM_PROJECT = "project"; | |||
public static final String PARAM_NAME = "name"; | |||
public static final String PARAM_BRANCH = "branch"; | |||
public static final String PARAM_ORGANIZATION = "organization"; | |||
public static final String PARAM_QUALIFIERS = "qualifiers"; | |||
private ProjectsWsParameters() { | |||
// static utils only |
@@ -0,0 +1,109 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 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.sonarqube.ws.client.project; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import static java.util.Objects.requireNonNull; | |||
public class SearchWsRequest { | |||
private final String organization; | |||
private final String query; | |||
private final List<String> qualifiers; | |||
private final Integer page; | |||
private final Integer pageSize; | |||
public SearchWsRequest(Builder builder) { | |||
this.organization = builder.organization; | |||
this.query = builder.query; | |||
this.qualifiers = builder.qualifiers; | |||
this.page = builder.page; | |||
this.pageSize = builder.pageSize; | |||
} | |||
@CheckForNull | |||
public String getOrganization() { | |||
return organization; | |||
} | |||
public List<String> getQualifiers() { | |||
return qualifiers; | |||
} | |||
@CheckForNull | |||
public Integer getPage() { | |||
return page; | |||
} | |||
@CheckForNull | |||
public Integer getPageSize() { | |||
return pageSize; | |||
} | |||
@CheckForNull | |||
public String getQuery() { | |||
return query; | |||
} | |||
public static Builder builder() { | |||
return new Builder(); | |||
} | |||
public static class Builder { | |||
private String organization; | |||
private List<String> qualifiers = new ArrayList<>(); | |||
private Integer page; | |||
private Integer pageSize; | |||
private String query; | |||
public Builder setOrganization(@Nullable String organization) { | |||
this.organization = organization; | |||
return this; | |||
} | |||
public Builder setQualifiers(List<String> qualifiers) { | |||
this.qualifiers = requireNonNull(qualifiers, "Qualifiers cannot be null"); | |||
return this; | |||
} | |||
public Builder setPage(@Nullable Integer page) { | |||
this.page = page; | |||
return this; | |||
} | |||
public Builder setPageSize(@Nullable Integer pageSize) { | |||
this.pageSize = pageSize; | |||
return this; | |||
} | |||
public Builder setQuery(@Nullable String query) { | |||
this.query = query; | |||
return this; | |||
} | |||
public SearchWsRequest build() { | |||
return new SearchWsRequest(this); | |||
} | |||
} | |||
} |
@@ -57,3 +57,17 @@ message CreateWsResponse { | |||
} | |||
} | |||
// WS api/projects/search | |||
message SearchWsResponse { | |||
optional sonarqube.ws.commons.Paging paging = 1; | |||
repeated Component components = 2; | |||
message Component { | |||
optional string organization = 1; | |||
optional string id = 2; | |||
optional string key = 3; | |||
optional string name = 4; | |||
optional string qualifier = 5; | |||
} | |||
} | |||
@@ -25,9 +25,12 @@ import org.sonarqube.ws.WsProjects; | |||
import org.sonarqube.ws.client.ServiceTester; | |||
import org.sonarqube.ws.client.WsConnector; | |||
import static java.util.Arrays.asList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.data.MapEntry.entry; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.api.server.ws.WebService.Param.PAGE; | |||
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; | |||
public class ProjectsServiceTest { | |||
@@ -96,4 +99,24 @@ public class ProjectsServiceTest { | |||
assertThat(serviceTester.getPostRequest().getPath()).isEqualTo("api/projects/delete"); | |||
assertThat(serviceTester.getPostRequest().getParams()).containsOnly(entry("key", "project_key")); | |||
} | |||
@Test | |||
public void search() { | |||
underTest.search(SearchWsRequest.builder() | |||
.setOrganization("default") | |||
.setQuery("project") | |||
.setQualifiers(asList("TRK", "VW")) | |||
.setPage(3) | |||
.setPageSize(10) | |||
.build()); | |||
serviceTester.assertThat(serviceTester.getGetRequest()) | |||
.hasPath("search") | |||
.hasParam("organization", "default") | |||
.hasParam("q", "project") | |||
.hasParam("qualifiers", "TRK,VW") | |||
.hasParam(PAGE, 3) | |||
.hasParam(PAGE_SIZE, 10) | |||
.andNoOtherParam(); | |||
} | |||
} |