Browse Source

SONAR-12259 - remove deprecated request params, response fields from api/projects (#1881)

* remove deprecated params from api/projects/bulk_delete
* remove deprecated projectsIds param
* update documentation for api/projects/bulk_delete

* remove deprecated params from api/projects/bulk_update_key
* remove deprecated params: key, projectId, id
* update documentation for api/projects/bulk_update_key

* remove deprecated params from api/projects/create
* remove deprecated param: key
* update documentation for api/projects/create

* remove deprecated params from api/projects/delete
* remove deprecated param: projectId, key
* update documentation for api/projects/delete

* remove deprecated apis: api/projects/ghosts | index | provisioned

* remove deprecated params from api/projects/search
* remove deprecated param: projectIds
* remove deprecated response fields: id (uuid)
* remove all usage of deprecated params: page, pageSize (remove associated tests)
* update documentation for api/projects/search

* remove deprecated params from api/projects/search_my_projects
* remove deprecated response fields: id (uuid)
* update documentation for api/projects/search_my_projects

* remove deprecated params from api/projects/update_key
* remove deprecated params: id, projectId, key, newKey
* change "from" param to be mandatory

* remove ProjectListTest.java file as endpoint does not exist anymore

* bump orchestrator version
* remove ComponentDao and ComponentMapper methods associated with deprecated code

* use "project" param when calling api/projects/create
* update ProjectDumpOperations#renameProjectKey to use api/projects/update_key endpoint

* use java api calls instead of URLs

*  bump orchestrator version to latest released 3.26.0.2111
tags/8.0
Jacek 4 years ago
parent
commit
44a69c7974
42 changed files with 91 additions and 2343 deletions
  1. 0
    13
      server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java
  2. 0
    6
      server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java
  3. 0
    51
      server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml
  4. 0
    97
      server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java
  5. 8
    22
      server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java
  6. 13
    45
      server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkUpdateKeyAction.java
  7. 9
    14
      server/sonar-server/src/main/java/org/sonar/server/project/ws/CreateAction.java
  8. 2
    11
      server/sonar-server/src/main/java/org/sonar/server/project/ws/DeleteAction.java
  9. 0
    156
      server/sonar-server/src/main/java/org/sonar/server/project/ws/GhostsAction.java
  10. 0
    154
      server/sonar-server/src/main/java/org/sonar/server/project/ws/IndexAction.java
  11. 0
    3
      server/sonar-server/src/main/java/org/sonar/server/project/ws/ProjectsWsModule.java
  12. 0
    165
      server/sonar-server/src/main/java/org/sonar/server/project/ws/ProvisionedAction.java
  13. 0
    17
      server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java
  14. 1
    3
      server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java
  15. 0
    14
      server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchRequest.java
  16. 8
    27
      server/sonar-server/src/main/java/org/sonar/server/project/ws/UpdateKeyAction.java
  17. 0
    2
      server/sonar-server/src/main/resources/org/sonar/server/project/ws/search-example.json
  18. 0
    2
      server/sonar-server/src/main/resources/org/sonar/server/project/ws/search_my_projects-example.json
  19. 0
    21
      server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
  20. 2
    2
      server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java
  21. 10
    59
      server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkUpdateKeyActionTest.java
  22. 17
    34
      server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java
  23. 2
    38
      server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java
  24. 0
    282
      server/sonar-server/src/test/java/org/sonar/server/project/ws/GhostsActionTest.java
  25. 0
    259
      server/sonar-server/src/test/java/org/sonar/server/project/ws/IndexActionTest.java
  26. 2
    2
      server/sonar-server/src/test/java/org/sonar/server/project/ws/ProjectsWsModuleTest.java
  27. 0
    226
      server/sonar-server/src/test/java/org/sonar/server/project/ws/ProvisionedActionTest.java
  28. 1
    28
      server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java
  29. 0
    7
      server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchMyProjectsActionTest.java
  30. 13
    74
      server/sonar-server/src/test/java/org/sonar/server/project/ws/UpdateKeyActionTest.java
  31. 2
    4
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ProjectsActionTest.java
  32. 0
    7
      server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/deprecated_paging.json
  33. 0
    2
      sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
  34. 0
    15
      sonar-ws/src/main/java/org/sonarqube/ws/client/projects/BulkDeleteRequest.java
  35. 1
    16
      sonar-ws/src/main/java/org/sonarqube/ws/client/projects/BulkUpdateKeyRequest.java
  36. 0
    14
      sonar-ws/src/main/java/org/sonarqube/ws/client/projects/DeleteRequest.java
  37. 0
    106
      sonar-ws/src/main/java/org/sonarqube/ws/client/projects/GhostsRequest.java
  38. 0
    151
      sonar-ws/src/main/java/org/sonarqube/ws/client/projects/IndexRequest.java
  39. 0
    71
      sonar-ws/src/main/java/org/sonarqube/ws/client/projects/ProjectsService.java
  40. 0
    106
      sonar-ws/src/main/java/org/sonarqube/ws/client/projects/ProvisionedRequest.java
  41. 0
    15
      sonar-ws/src/main/java/org/sonarqube/ws/client/projects/UpdateKeyRequest.java
  42. 0
    2
      sonar-ws/src/main/protobuf/ws-projects.proto

+ 0
- 13
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java View File

@@ -313,14 +313,6 @@ public class ComponentDao implements Dao {
return mapper(dbSession).selectProjectsByOrganization(organizationUuid);
}

public List<ComponentDto> selectGhostProjects(DbSession session, String organizationUuid, @Nullable String query, int offset, int limit) {
return mapper(session).selectGhostProjects(organizationUuid, buildUpperLikeSql(query), new RowBounds(offset, limit));
}

public long countGhostProjects(DbSession session, String organizationUuid, @Nullable String query) {
return mapper(session).countGhostProjects(organizationUuid, buildUpperLikeSql(query));
}

/**
* Selects all components that are relevant for indexing. The result is not returned (since it is usually too big), but handed over to the <code>handler</code>
*
@@ -355,11 +347,6 @@ public class ComponentDao implements Dao {
return mapper(dbSession).selectEnabledComponentsWithModuleUuidFromProjectKey(projectKey);
}

public List<ComponentDto> selectProjectsByNameQuery(DbSession dbSession, @Nullable String nameQuery, boolean includeModules) {
String nameQueryForSql = nameQuery == null ? null : buildLikeValue(nameQuery, BEFORE_AND_AFTER).toUpperCase(Locale.ENGLISH);
return mapper(dbSession).selectProjectsByNameQuery(nameQueryForSql, includeModules);
}

/**
* Returns components with open issues from branches that use a certain long living branch as reference (merge branch).
* Excludes components from the current branch.

+ 0
- 6
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java View File

@@ -138,12 +138,6 @@ public interface ComponentMapper {
*/
List<String> selectProjectsFromView(@Param("viewUuidLikeQuery") String viewUuidLikeQuery, @Param("projectViewUuid") String projectViewUuid);

List<ComponentDto> selectGhostProjects(@Param("organizationUuid") String organizationUuid, @Nullable @Param("query") String query, RowBounds rowBounds);

long countGhostProjects(@Param("organizationUuid") String organizationUuid, @Nullable @Param("query") String query);

List<ComponentDto> selectProjectsByNameQuery(@Param("nameQuery") @Nullable String nameQuery, @Param("includeModules") boolean includeModules);

void scrollForIndexing(@Param("projectUuid") @Nullable String projectUuid, ResultHandler<ComponentDto> handler);

void scrollAllFilesForFileMove(@Param("projectUuid") String projectUuid, ResultHandler<FileMoveRowDto> handler);

+ 0
- 51
server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml View File

@@ -535,36 +535,6 @@
projects root ON root.uuid=p.project_uuid AND root.kee=#{projectKey,jdbcType=VARCHAR}
</select>

<select id="selectGhostProjects" parameterType="map" resultType="Component">
select distinct
<include refid="componentColumns"/>
from projects p
<include refid="ghostProjectClauses"/>
</select>

<select id="countGhostProjects" parameterType="map" resultType="long">
select
count(distinct p.id)
from projects p
<include refid="ghostProjectClauses"/>
</select>

<sql id="ghostProjectClauses">
inner join snapshots s1 on s1.component_uuid = p.uuid and s1.status='U'
left join snapshots s2 on s2.component_uuid = p.uuid and s2.status='P'
where
s2.id is null
and p.qualifier='TRK'
and p.main_branch_project_uuid is null
and p.copy_component_uuid is null
<if test="query!=null">
and (
UPPER(p.name) like #{query} ESCAPE '/'
or UPPER(p.kee) like #{query} ESCAPE '/'
)
</if>
</sql>

<select id="scrollForIndexing" parameterType="map" resultType="Component" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
select
<include refid="componentColumns"/>
@@ -596,27 +566,6 @@
and p.path is not null
</select>

<select id="selectProjectsByNameQuery" resultType="Component">
select
<include refid="componentColumns"/>
from projects p
<where>
p.enabled=${_true}
AND p.main_branch_project_uuid is null
AND p.copy_component_uuid is null
<if test="includeModules == false">
AND p.qualifier = 'TRK'
</if>
<if test="includeModules == true">
AND (p.qualifier = 'TRK' OR p.qualifier = 'BRC')
</if>
<if test="nameQuery != null">
AND UPPER(p.name) like #{nameQuery,jdbcType=VARCHAR} ESCAPE '/'
</if>
</where>
ORDER BY p.name
</select>

<insert id="insert" parameterType="Component" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
INSERT INTO projects (
organization_uuid,

+ 0
- 97
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java View File

@@ -1228,61 +1228,6 @@ public class ComponentDaoTest {
underTest.countByQuery(dbSession, query.build());
}

@Test
public void select_ghost_projects() {
OrganizationDto organization = db.organizations().insert();

// ghosts because has at least one snapshot with status U but none with status P
ComponentDto ghostProject = db.components().insertPrivateProject(organization);
db.components().insertSnapshot(ghostProject, dto -> dto.setStatus("U"));
db.components().insertSnapshot(ghostProject, dto -> dto.setStatus("U"));
ComponentDto ghostProject2 = db.components().insertPrivateProject(organization);
db.components().insertSnapshot(ghostProject2, dto -> dto.setStatus("U"));
ComponentDto disabledGhostProject = db.components().insertPrivateProject(dto -> dto.setEnabled(false));
db.components().insertSnapshot(disabledGhostProject, dto -> dto.setStatus("U"));

ComponentDto project1 = db.components().insertPrivateProject(organization);
db.components().insertSnapshot(project1, dto -> dto.setStatus("P"));
db.components().insertSnapshot(project1, dto -> dto.setStatus("U"));
ComponentDto module = db.components().insertComponent(newModuleDto(project1));
ComponentDto dir = db.components().insertComponent(newDirectory(module, "foo"));
db.components().insertComponent(newFileDto(module, dir, "bar"));

ComponentDto provisionedProject = db.components().insertPrivateProject(organization);

// not a ghost because has at least one snapshot with status P
ComponentDto project2 = db.components().insertPrivateProject(organization);
db.components().insertSnapshot(project2, dto -> dto.setStatus("P"));

// not a ghost because it's not a project
ComponentDto view = db.components().insertView(organization);
db.components().insertSnapshot(view, dto -> dto.setStatus("U"));
db.components().insertComponent(newProjectCopy("do", project1, view));

assertThat(underTest.selectGhostProjects(dbSession, organization.getUuid(), null, 0, 10))
.extracting(ComponentDto::uuid)
.containsOnly(ghostProject.uuid(), ghostProject2.uuid(), disabledGhostProject.uuid());
assertThat(underTest.countGhostProjects(dbSession, organization.getUuid(), null)).isEqualTo(3);
}

@Test
public void dont_select_branch_ghost_projects() {
OrganizationDto organization = db.organizations().insert();

// ghosts because has at least one snapshot with status U but none with status P
ComponentDto ghostProject = db.components().insertPrivateProject(organization);
db.components().insertSnapshot(ghostProject, dto -> dto.setStatus("U"));
db.components().insertSnapshot(ghostProject, dto -> dto.setStatus("U"));
ComponentDto ghostBranchProject = db.components().insertProjectBranch(ghostProject);

db.components().insertSnapshot(ghostBranchProject, dto -> dto.setStatus("U"));

assertThat(underTest.selectGhostProjects(dbSession, organization.getUuid(), null, 0, 10))
.extracting(ComponentDto::uuid)
.containsOnly(ghostProject.uuid());
assertThat(underTest.countGhostProjects(dbSession, organization.getUuid(), null)).isEqualTo(1);
}

@Test
public void selectByProjectUuid() {
ComponentDto project = db.components().insertPrivateProject();
@@ -1945,48 +1890,6 @@ public class ComponentDaoTest {
assertThat(components).extracting("organizationUuid").containsOnly(organizationDto.getUuid());
}

@Test
public void select_projects_by_name_ignore_branches() {
OrganizationDto organizationDto = db.organizations().insert();
ComponentDto project1 = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto).setName("project1"));
ComponentDto module1 = db.components().insertComponent(newModuleDto(project1).setName("project1"));
ComponentDto subModule1 = db.components().insertComponent(newModuleDto(module1).setName("project1"));

db.components().insertComponent(newFileDto(subModule1).setName("project1"));
db.components().insertProjectBranch(project1, b -> b.setKey("branch1"));

// check that branch is present with same name as main branch
assertThat(underTest.selectByKeyAndBranch(dbSession, project1.getKey(), "branch1").get().name()).isEqualTo("project1");

// branch is not returned
assertThat(underTest.selectProjectsByNameQuery(dbSession, null, false)).extracting(ComponentDto::uuid)
.containsOnly(project1.uuid());
assertThat(underTest.selectProjectsByNameQuery(dbSession, "project", false)).extracting(ComponentDto::uuid)
.containsOnly(project1.uuid());
}

@Test
public void select_projects_by_name_query() {
OrganizationDto organizationDto = db.organizations().insert();
ComponentDto project1 = db.components().insertComponent(newPrivateProjectDto(organizationDto).setName("project1"));
ComponentDto module1 = db.components().insertComponent(newModuleDto(project1).setName("module1"));
ComponentDto subModule1 = db.components().insertComponent(newModuleDto(module1).setName("subModule1"));
db.components().insertComponent(newFileDto(subModule1).setName("file"));
ComponentDto project2 = db.components().insertComponent(newPrivateProjectDto(organizationDto).setName("project2"));
ComponentDto project3 = db.components().insertComponent(newPrivateProjectDto(organizationDto).setName("project3"));

assertThat(underTest.selectProjectsByNameQuery(dbSession, null, false)).extracting(ComponentDto::uuid)
.containsOnly(project1.uuid(), project2.uuid(), project3.uuid());
assertThat(underTest.selectProjectsByNameQuery(dbSession, null, true)).extracting(ComponentDto::uuid)
.containsOnly(project1.uuid(), project2.uuid(), project3.uuid(), module1.uuid(), subModule1.uuid());
assertThat(underTest.selectProjectsByNameQuery(dbSession, "project1", false)).extracting(ComponentDto::uuid).containsOnly(project1.uuid());
assertThat(underTest.selectProjectsByNameQuery(dbSession, "ct1", false)).extracting(ComponentDto::uuid).containsOnly(project1.uuid());
assertThat(underTest.selectProjectsByNameQuery(dbSession, "pro", false)).extracting(ComponentDto::uuid).containsOnly(project1.uuid(), project2.uuid(), project3.uuid());
assertThat(underTest.selectProjectsByNameQuery(dbSession, "jec", false)).extracting(ComponentDto::uuid).containsOnly(project1.uuid(), project2.uuid(), project3.uuid());
assertThat(underTest.selectProjectsByNameQuery(dbSession, "1", true)).extracting(ComponentDto::uuid).containsOnly(project1.uuid(), module1.uuid(), subModule1.uuid());
assertThat(underTest.selectProjectsByNameQuery(dbSession, "unknown", true)).extracting(ComponentDto::uuid).isEmpty();
}

@Test
public void setPrivateForRootComponentUuid_updates_private_column_to_specified_value_for_all_rows_with_specified_projectUuid() {
String uuid1 = "uuid1";

+ 8
- 22
server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java View File

@@ -47,8 +47,6 @@ import static java.lang.String.format;
import static org.sonar.api.resources.Qualifiers.APP;
import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.VIEW;
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
import static org.sonar.server.project.ws.SearchAction.buildDbQuery;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002;
@@ -56,7 +54,6 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZE
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_IDS;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;

@@ -81,35 +78,26 @@ public class BulkDeleteAction implements ProjectsWsAction {

@Override
public void define(WebService.NewController context) {
String parameterRequiredMessage = format("At least one parameter is required among %s, %s, %s (deprecated since 6.4) and %s",
PARAM_ANALYZED_BEFORE, PARAM_PROJECTS, PARAM_PROJECT_IDS, Param.TEXT_QUERY);
String parameterRequiredMessage = format("At least one parameter is required among %s, %s and %s",
PARAM_ANALYZED_BEFORE, PARAM_PROJECTS, Param.TEXT_QUERY);
WebService.NewAction action = context
.createAction(ACTION)
.setPost(true)
.setDescription("Delete one or several projects.<br />" +
"Only the 1'000 first items in project filters are taken into account.<br />" +
"Requires 'Administer System' permission.<br />" +
parameterRequiredMessage)
.setSince("5.2")
.setHandler(this)
.setChangelog(
new Change("7.8", parameterRequiredMessage),
new Change("6.7.2", "Only the 1'000 first items in project filters are taken into account"));
.setChangelog(new Change("7.8", parameterRequiredMessage));

support.addOrganizationParam(action);

action
.createParam(PARAM_PROJECTS)
.setDescription("Comma-separated list of project keys")
.setDeprecatedKey("keys", "6.4")
.setExampleValue(String.join(",", KEY_PROJECT_EXAMPLE_001, KEY_PROJECT_EXAMPLE_002));

action
.createParam(PARAM_PROJECT_IDS)
.setDescription("Comma-separated list of project ids. Only the 1'000 first ids are used. Others are silently ignored.")
.setDeprecatedKey("ids", "6.4")
.setDeprecatedSince("6.4")
.setExampleValue(String.join(",", UUID_EXAMPLE_01, UUID_EXAMPLE_02));

action.createParam(Param.TEXT_QUERY)
.setDescription("Limit to: <ul>" +
"<li>component names that contain the supplied string</li>" +
@@ -168,13 +156,12 @@ public class BulkDeleteAction implements ProjectsWsAction {
boolean analyzedBeforePresent = !Strings.isNullOrEmpty(searchRequest.getAnalyzedBefore());
List<String> projects = searchRequest.getProjects();
boolean projectsPresent = projects != null && !projects.isEmpty();
List<String> projectIds = searchRequest.getProjectIds();
boolean projectIdsPresent = projectIds != null && !projectIds.isEmpty();

boolean queryPresent = !Strings.isNullOrEmpty(searchRequest.getQuery());
boolean atLeastOneParameterIsPresent = analyzedBeforePresent || projectsPresent || queryPresent || projectIdsPresent;
boolean atLeastOneParameterIsPresent = analyzedBeforePresent || projectsPresent || queryPresent;

checkArgument(atLeastOneParameterIsPresent, format("At lease one parameter among %s, %s, %s, and %s must be provided",
PARAM_ANALYZED_BEFORE, PARAM_PROJECTS, PARAM_PROJECT_IDS, Param.TEXT_QUERY));
checkArgument(atLeastOneParameterIsPresent, format("At lease one parameter among %s, %s and %s must be provided",
PARAM_ANALYZED_BEFORE, PARAM_PROJECTS, Param.TEXT_QUERY));
}

private static SearchRequest toSearchWsRequest(Request request) {
@@ -186,7 +173,6 @@ public class BulkDeleteAction implements ProjectsWsAction {
.setAnalyzedBefore(request.param(PARAM_ANALYZED_BEFORE))
.setOnProvisionedOnly(request.mandatoryParamAsBoolean(PARAM_ON_PROVISIONED_ONLY))
.setProjects(restrictTo1000Values(request.paramAsStrings(PARAM_PROJECTS)))
.setProjectIds(restrictTo1000Values(request.paramAsStrings(PARAM_PROJECT_IDS)))
.build();
}


+ 13
- 45
server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkUpdateKeyAction.java View File

@@ -22,7 +22,6 @@ package org.sonar.server.project.ws;
import com.google.common.collect.ImmutableList;
import java.util.Comparator;
import java.util.Map;
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;
@@ -32,16 +31,11 @@ import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentKeyUpdaterDao;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.component.ComponentFinder.ParamNames;
import org.sonar.server.component.ComponentService;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Projects.BulkUpdateKeyWsResponse;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
import static org.sonar.db.component.ComponentKeyUpdaterDao.checkIsProjectOrModule;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
@@ -49,7 +43,6 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_BULK_U
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_DRY_RUN;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_FROM;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_TO;

public class BulkUpdateKeyAction implements ProjectsWsAction {
@@ -83,33 +76,22 @@ public class BulkUpdateKeyAction implements ProjectsWsAction {
" <li>%s: my_</li>" +
" <li>%s: my_new_</li>" +
"</ul>" +
"Either '%s' or '%s' must be provided.<br> " +
"Requires one of the following permissions: " +
"<ul>" +
"<li>'Administer System'</li>" +
"<li>'Administer' rights on the specified project</li>" +
"</ul>",
PARAM_DRY_RUN,
PARAM_PROJECT, PARAM_FROM, PARAM_TO,
PARAM_PROJECT_ID, PARAM_PROJECT)
PARAM_PROJECT, PARAM_FROM, PARAM_TO)
.setDeprecatedSince("7.6")
.setSince("6.1")
.setPost(true)
.setResponseExample(getClass().getResource("bulk_update_key-example.json"))
.setHandler(this);

action.setChangelog(
new Change("6.4", "Moved from api/components/bulk_update_key to api/projects/bulk_update_key"));

action.createParam(PARAM_PROJECT_ID)
.setDescription("Project or module ID")
.setDeprecatedKey("id", "6.4")
.setDeprecatedSince("6.4")
.setExampleValue(UUID_EXAMPLE_01);

action.createParam(PARAM_PROJECT)
.setDescription("Project or module key")
.setDeprecatedKey("key", "6.4")
.setRequired(true)
.setExampleValue("my_old_project");

action.createParam(PARAM_FROM)
@@ -137,7 +119,7 @@ public class BulkUpdateKeyAction implements ProjectsWsAction {

private BulkUpdateKeyWsResponse doHandle(BulkUpdateKeyRequest request) {
try (DbSession dbSession = dbClient.openSession(false)) {
ComponentDto projectOrModule = componentFinder.getByUuidOrKey(dbSession, request.getId(), request.getKey(), ParamNames.ID_AND_KEY);
ComponentDto projectOrModule = componentFinder.getByKey(dbSession, request.getProjectKey());
checkIsProjectOrModule(projectOrModule);
userSession.checkComponentPermission(UserRole.ADMIN, projectOrModule);

@@ -154,7 +136,7 @@ public class BulkUpdateKeyAction implements ProjectsWsAction {
}

private static void checkNoDuplicate(Map<String, Boolean> newKeysWithDuplicateMap) {
newKeysWithDuplicateMap.entrySet().forEach(entry -> checkRequest(!entry.getValue(), "Impossible to update key: a component with key \"%s\" already exists.", entry.getKey()));
newKeysWithDuplicateMap.forEach((key, value) -> checkRequest(!value, "Impossible to update key: a component with key \"%s\" already exists.", key));
}

private void bulkUpdateKey(DbSession dbSession, BulkUpdateKeyRequest request, ComponentDto projectOrModule) {
@@ -181,8 +163,7 @@ public class BulkUpdateKeyAction implements ProjectsWsAction {

private static BulkUpdateKeyRequest toWsRequest(Request request) {
return BulkUpdateKeyRequest.builder()
.setId(request.param(PARAM_PROJECT_ID))
.setKey(request.param(PARAM_PROJECT))
.setProjectKey(request.mandatoryParam(PARAM_PROJECT))
.setFrom(request.mandatoryParam(PARAM_FROM))
.setTo(request.mandatoryParam(PARAM_TO))
.setDryRun(request.mandatoryParamAsBoolean(PARAM_DRY_RUN))
@@ -190,28 +171,20 @@ public class BulkUpdateKeyAction implements ProjectsWsAction {
}

private static class BulkUpdateKeyRequest {
private final String id;
private final String key;
private final String projectKey;
private final String from;
private final String to;
private final boolean dryRun;

public BulkUpdateKeyRequest(Builder builder) {
this.id = builder.id;
this.key = builder.key;
this.projectKey = builder.projectKey;
this.from = builder.from;
this.to = builder.to;
this.dryRun = builder.dryRun;
}

@CheckForNull
public String getId() {
return id;
}

@CheckForNull
public String getKey() {
return key;
public String getProjectKey() {
return projectKey;
}

public String getFrom() {
@@ -232,8 +205,7 @@ public class BulkUpdateKeyAction implements ProjectsWsAction {
}

public static class Builder {
private String id;
private String key;
private String projectKey;
private String from;
private String to;
private boolean dryRun;
@@ -242,13 +214,8 @@ public class BulkUpdateKeyAction implements ProjectsWsAction {
// enforce method constructor
}

public Builder setId(@Nullable String id) {
this.id = id;
return this;
}

public Builder setKey(@Nullable String key) {
this.key = key;
public Builder setProjectKey(String projectKey) {
this.projectKey = projectKey;
return this;
}

@@ -268,6 +235,7 @@ public class BulkUpdateKeyAction implements ProjectsWsAction {
}

public BulkUpdateKeyRequest build() {
checkArgument(projectKey != null && !projectKey.isEmpty(), "The key must not be empty");
checkArgument(from != null && !from.isEmpty(), "The string to match must not be empty");
checkArgument(to != null && !to.isEmpty(), "The string replacement must not be empty");
return new BulkUpdateKeyRequest(this);

+ 9
- 14
server/sonar-server/src/main/java/org/sonar/server/project/ws/CreateAction.java View File

@@ -51,8 +51,6 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBIL

public class CreateAction implements ProjectsWsAction {

private static final String DEPRECATED_PARAM_KEY = "key";

private final ProjectsWsSupport support;
private final DbClient dbClient;
private final UserSession userSession;
@@ -76,13 +74,10 @@ public class CreateAction implements ProjectsWsAction {
.setHandler(this);

action.setChangelog(
new Change("6.3", "The response format has been updated and does not contain the database ID anymore"),
new Change("6.3", "The 'key' parameter has been renamed 'project'"),
new Change("7.1", "The 'visibility' parameter is public"));

action.createParam(PARAM_PROJECT)
.setDescription("Key of the project")
.setDeprecatedKey(DEPRECATED_PARAM_KEY, "6.3")
.setRequired(true)
.setMaximumLength(MAX_COMPONENT_KEY_LENGTH)
.setExampleValue(KEY_PROJECT_EXAMPLE_001);
@@ -123,7 +118,7 @@ public class CreateAction implements ProjectsWsAction {

ComponentDto componentDto = componentUpdater.create(dbSession, newComponentBuilder()
.setOrganizationUuid(organization.getUuid())
.setKey(request.getKey())
.setKey(request.getProjectKey())
.setName(request.getName())
.setDeprecatedBranch(request.getBranch())
.setPrivate(changeToPrivate)
@@ -137,7 +132,7 @@ public class CreateAction implements ProjectsWsAction {
private static CreateRequest toCreateRequest(Request request) {
return CreateRequest.builder()
.setOrganization(request.param(PARAM_ORGANIZATION))
.setKey(request.mandatoryParam(PARAM_PROJECT))
.setProjectKey(request.mandatoryParam(PARAM_PROJECT))
.setName(abbreviate(request.mandatoryParam(PARAM_NAME), MAX_COMPONENT_NAME_LENGTH))
.setBranch(request.param(PARAM_BRANCH))
.setVisibility(request.param(PARAM_VISIBILITY))
@@ -157,7 +152,7 @@ public class CreateAction implements ProjectsWsAction {
static class CreateRequest {

private final String organization;
private final String key;
private final String projectKey;
private final String name;
private final String branch;
@CheckForNull
@@ -165,7 +160,7 @@ public class CreateAction implements ProjectsWsAction {

private CreateRequest(Builder builder) {
this.organization = builder.organization;
this.key = builder.key;
this.projectKey = builder.projectKey;
this.name = builder.name;
this.branch = builder.branch;
this.visibility = builder.visibility;
@@ -177,8 +172,8 @@ public class CreateAction implements ProjectsWsAction {
}

@CheckForNull
public String getKey() {
return key;
public String getProjectKey() {
return projectKey;
}

@CheckForNull
@@ -203,7 +198,7 @@ public class CreateAction implements ProjectsWsAction {

static class Builder {
private String organization;
private String key;
private String projectKey;
private String name;
private String branch;
@CheckForNull
@@ -217,8 +212,8 @@ public class CreateAction implements ProjectsWsAction {
return this;
}

public Builder setKey(@Nullable String key) {
this.key = key;
public Builder setProjectKey(@Nullable String projectKey) {
this.projectKey = projectKey;
return this;
}


+ 2
- 11
server/sonar-server/src/main/java/org/sonar/server/project/ws/DeleteAction.java View File

@@ -67,17 +67,9 @@ public class DeleteAction implements ProjectsWsAction {
.setSince("5.2")
.setHandler(this);

action
.createParam(PARAM_PROJECT_ID)
.setDescription("Project ID")
.setDeprecatedKey("id", "6.4")
.setDeprecatedSince("6.4")
.setExampleValue("ce4c03d6-430f-40a9-b777-ad877c00aa4d");

action
.createParam(PARAM_PROJECT)
.setDescription("Project key")
.setDeprecatedKey("key", "6.4")
.setExampleValue(KEY_PROJECT_EXAMPLE_001);
}

@@ -85,11 +77,10 @@ public class DeleteAction implements ProjectsWsAction {
public void handle(Request request, Response response) throws Exception {
// fail-fast if not logged in
userSession.checkLoggedIn();
String uuid = request.param(PARAM_PROJECT_ID);
String key = request.param(PARAM_PROJECT);
String key = request.mandatoryParam(PARAM_PROJECT);

try (DbSession dbSession = dbClient.openSession(false)) {
ComponentDto project = componentFinder.getByUuidOrKey(dbSession, uuid, key, PROJECT_ID_AND_PROJECT);
ComponentDto project = componentFinder.getByKey(dbSession, key);
checkPermission(project);
componentCleanerService.delete(dbSession, project);
projectLifeCycleListeners.onProjectsDeleted(singleton(from(project)));

+ 0
- 156
server/sonar-server/src/main/java/org/sonar/server/project/ws/GhostsAction.java View File

@@ -1,156 +0,0 @@
/*
* 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.server.project.ws;

import com.google.common.io.Resources;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
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.api.server.ws.WebService.Param;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.user.UserSession;

import static com.google.common.collect.Sets.newHashSet;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
import static org.sonar.server.project.Visibility.PRIVATE;
import static org.sonar.server.project.Visibility.PUBLIC;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;

public class GhostsAction implements ProjectsWsAction {
private static final String PARAM_ORGANIZATION = "organization";
private static final String ACTION = "ghosts";
private static final Set<String> POSSIBLE_FIELDS = newHashSet("uuid", "key", "name", "creationDate", "visibility");

private final DbClient dbClient;
private final UserSession userSession;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public GhostsAction(DbClient dbClient, UserSession userSession, DefaultOrganizationProvider defaultOrganizationProvider) {
this.dbClient = dbClient;
this.userSession = userSession;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction(ACTION);

action.setChangelog(new Change("6.4", "The 'uuid' field is deprecated in the response"));

action
.setDescription("List ghost projects.<br> " +
"With the current architecture, it's no more possible to have invisible ghost projects. Therefore, the web service is deprecated.<br> " +
"Requires 'Administer System' permission.")
.setResponseExample(Resources.getResource(getClass(), "ghosts-example.json"))
.setSince("5.2")
.setDeprecatedSince("6.6")
.addPagingParams(100, MAX_LIMIT)
.addFieldsParam(POSSIBLE_FIELDS)
.addSearchQuery("sonar", "names", "keys")
.setHandler(this);

action.createParam(PARAM_ORGANIZATION)
.setDescription("Organization key")
.setRequired(false)
.setInternal(true)
.setSince("6.3");
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn();

SearchOptions searchOptions = new SearchOptions()
.setPage(request.mandatoryParamAsInt(Param.PAGE),
request.mandatoryParamAsInt(Param.PAGE_SIZE));
Set<String> desiredFields = fieldsToReturn(request.paramAsStrings(Param.FIELDS));
String query = request.param(Param.TEXT_QUERY);

try (DbSession dbSession = dbClient.openSession(false)) {
OrganizationDto organization = getOrganization(dbSession, request);
userSession.checkPermission(ADMINISTER, organization);

long nbOfProjects = dbClient.componentDao().countGhostProjects(dbSession, organization.getUuid(), query);
List<ComponentDto> projects = dbClient.componentDao().selectGhostProjects(dbSession, organization.getUuid(), query,
searchOptions.getOffset(), searchOptions.getLimit());
try (JsonWriter json = response.newJsonWriter()) {
json.beginObject();
writeProjects(json, projects, desiredFields);
searchOptions.writeJson(json, nbOfProjects);
json.endObject();
}
}
}

private OrganizationDto getOrganization(DbSession dbSession, Request request) {
String organizationKey = request.getParam(PARAM_ORGANIZATION)
.or(defaultOrganizationProvider.get()::getKey);
return checkFoundWithOptional(
dbClient.organizationDao().selectByKey(dbSession, organizationKey),
"No organization for key '%s'", organizationKey);
}

private static void writeProjects(JsonWriter json, List<ComponentDto> projects, Set<String> fieldsToReturn) {
json.name("projects");
json.beginArray();
for (ComponentDto project : projects) {
json.beginObject();
json.prop("uuid", project.uuid());
writeIfWished(json, "key", project.getDbKey(), fieldsToReturn);
writeIfWished(json, "name", project.name(), fieldsToReturn);
writeIfWished(json, "creationDate", project.getCreatedAt(), fieldsToReturn);
writeIfWished(json, "visibility", project.isPrivate() ? PRIVATE.getLabel() : PUBLIC.getLabel(), fieldsToReturn);
json.endObject();
}
json.endArray();
}

private static void writeIfWished(JsonWriter json, String key, String value, Set<String> fieldsToReturn) {
if (fieldsToReturn.contains(key)) {
json.prop(key, value);
}
}

private static void writeIfWished(JsonWriter json, String key, Date value, Set<String> desiredFields) {
if (desiredFields.contains(key)) {
json.propDateTime(key, value);
}
}

private static Set<String> fieldsToReturn(@Nullable List<String> desiredFieldsFromRequest) {
if (desiredFieldsFromRequest == null) {
return POSSIBLE_FIELDS;
}

return newHashSet(desiredFieldsFromRequest);
}
}

+ 0
- 154
server/sonar-server/src/main/java/org/sonar/server/project/ws/IndexAction.java View File

@@ -1,154 +0,0 @@
/*
* 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.server.project.ws;

import com.google.common.io.Resources;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
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.api.utils.text.JsonWriter;
import org.sonar.api.web.UserRole;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.user.UserSession;

import static java.util.Optional.ofNullable;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_INDEX;

/**
* This web service is used by old version of SonarLint.
*/
public class IndexAction implements ProjectsWsAction {

private static final String PARAM_PROJECT = "project";
private static final String PARAM_SEARCH = "search";
private static final String PARAM_SUB_PROJECTS = "subprojects";
private static final String PARAM_FORMAT = "format";

private final DbClient dbClient;
private final UserSession userSession;

public IndexAction(DbClient dbClient, UserSession userSession) {
this.dbClient = dbClient;
this.userSession = userSession;
}

@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction(ACTION_INDEX)
.setDescription("This web service is deprecated, please use api/components/search instead")
.setSince("2.10")
.setDeprecatedSince("6.3")
.setHandler(this)
.setResponseExample(Resources.getResource(this.getClass(), "index-example.json"));

action.setChangelog(
new Change("6.3", "The parameters 'desc', 'views', 'libs' and 'versions' have no effect."));

action.createParam(PARAM_PROJECT)
.setDescription("key or ID of the project")
.setDeprecatedKey("key", "6.4")
.setExampleValue(KEY_PROJECT_EXAMPLE_001);

action.createParam(PARAM_SEARCH)
.setDescription("Substring of project name, case insensitive. Ignored if the parameter key is set")
.setExampleValue("Sonar");
action.createParam(PARAM_SUB_PROJECTS)
.setDescription("Load sub-projects. Ignored if the parameter key is set")
.setDefaultValue("false")
.setBooleanPossibleValues();

action.createParam(PARAM_FORMAT)
.setDescription("Only json response format is available")
.setPossibleValues("json");

addRemovedParameter("desc", action);
addRemovedParameter("views", action);
addRemovedParameter("libs", action);
addRemovedParameter("versions", action);
}

@Override
public void handle(Request request, Response response) throws Exception {
try (DbSession dbSession = dbClient.openSession(false)) {
List<ComponentDto> projects = getAuthorizedComponents(searchComponents(dbSession, request))
.stream()
.filter(p -> p.getMainBranchProjectUuid() == null)
.collect(MoreCollectors.toList());
JsonWriter json = response.newJsonWriter();
json.beginArray();
for (ComponentDto project : projects) {
addProject(json, project);
}
json.endArray();
json.close();
}
}

private List<ComponentDto> searchComponents(DbSession dbSession, Request request) {
String projectKey = request.param(PARAM_PROJECT);
List<ComponentDto> projects = new ArrayList<>();
if (projectKey != null) {
getProjectByKeyOrId(dbSession, projectKey).ifPresent(projects::add);
} else {
String nameQuery = request.param(PARAM_SEARCH);
boolean includeModules = request.paramAsBoolean(PARAM_SUB_PROJECTS);
projects.addAll(dbClient.componentDao().selectProjectsByNameQuery(dbSession, nameQuery, includeModules));
}
return projects;
}

private Optional<ComponentDto> getProjectByKeyOrId(DbSession dbSession, String component) {
try {
long componentId = Long.parseLong(component);
return ofNullable(dbClient.componentDao().selectById(dbSession, componentId).orElse(null));
} catch (NumberFormatException e) {
return ofNullable(dbClient.componentDao().selectByKey(dbSession, component).orElse(null));
}
}

private List<ComponentDto> getAuthorizedComponents(List<ComponentDto> components) {
return userSession.keepAuthorizedComponents(UserRole.USER, components);
}

private static void addProject(JsonWriter json, ComponentDto project) {
json.beginObject()
.prop("id", project.getId())
.prop("k", project.getDbKey())
.prop("nm", project.name())
.prop("sc", project.scope())
.prop("qu", project.qualifier())
.endObject();
}

private static void addRemovedParameter(String key, WebService.NewAction action) {
action.createParam(key)
.setDescription("Since 6.3, this parameter has no effect")
.setDeprecatedSince("6.3");
}

}

+ 0
- 3
server/sonar-server/src/main/java/org/sonar/server/project/ws/ProjectsWsModule.java View File

@@ -39,13 +39,10 @@ public class ProjectsWsModule extends Module {
ProjectsWsSupport.class,
ProjectsWs.class,
CreateAction.class,
IndexAction.class,
BulkDeleteAction.class,
DeleteAction.class,
UpdateKeyAction.class,
BulkUpdateKeyAction.class,
GhostsAction.class,
ProvisionedAction.class,
SearchMyProjectsAction.class,
SearchAction.class,
UpdateVisibilityAction.class);

+ 0
- 165
server/sonar-server/src/main/java/org/sonar/server/project/ws/ProvisionedAction.java View File

@@ -1,165 +0,0 @@
/*
* 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.server.project.ws;

import com.google.common.io.Resources;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.sonar.api.resources.Qualifiers;
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.api.server.ws.WebService.Param;
import org.sonar.api.utils.DateUtils;
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.user.UserSession;
import org.sonarqube.ws.Common.Paging;
import org.sonarqube.ws.Components.ProvisionedWsResponse;
import org.sonarqube.ws.Components.ProvisionedWsResponse.Component;

import static com.google.common.collect.Sets.newHashSet;
import static java.util.Optional.ofNullable;
import static org.sonar.api.utils.Paging.offset;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
import static org.sonar.server.project.Visibility.PRIVATE;
import static org.sonar.server.project.Visibility.PUBLIC;
import static org.sonar.server.project.ws.ProjectsWsSupport.PARAM_ORGANIZATION;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class ProvisionedAction implements ProjectsWsAction {

private static final Set<String> POSSIBLE_FIELDS = newHashSet("uuid", "key", "name", "creationDate", "visibility");

private final ProjectsWsSupport support;
private final DbClient dbClient;
private final UserSession userSession;

public ProvisionedAction(ProjectsWsSupport support, DbClient dbClient, UserSession userSession) {
this.support = support;
this.dbClient = dbClient;
this.userSession = userSession;
}

@Override
public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction("provisioned");
action
.setDescription(
"Get the list of provisioned projects.<br> " +
"Web service is deprecated. Use api/projects/search instead, with onProvisionedOnly=true.<br> " +
"Require 'Create Projects' permission.")
.setSince("5.2")
.setDeprecatedSince("6.6")
.setResponseExample(Resources.getResource(getClass(), "provisioned-example.json"))
.setHandler(this)
.addPagingParams(100, MAX_LIMIT)
.addSearchQuery("sonar", "names", "keys")
.addFieldsParam(POSSIBLE_FIELDS);

action.setChangelog(
new Change("6.4", "The 'uuid' field is deprecated in the response"),
new Change("6.4", "Paging response fields is now in a Paging object"));

support.addOrganizationParam(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn();

int page = request.mandatoryParamAsInt(Param.PAGE);
int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
Set<String> desiredFields = desiredFields(request);
String query = request.param(Param.TEXT_QUERY);

try (DbSession dbSession = dbClient.openSession(false)) {
OrganizationDto organization = support.getOrganization(dbSession, request.param(PARAM_ORGANIZATION));
userSession.checkPermission(PROVISION_PROJECTS, organization);

ComponentQuery dbQuery = buildDbQuery(query);
List<ComponentDto> projects = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), dbQuery, offset(page, pageSize), pageSize);
int nbOfProjects = dbClient.componentDao().countByQuery(dbSession, organization.getUuid(), dbQuery);

ProvisionedWsResponse result = ProvisionedWsResponse.newBuilder()
.addAllProjects(writeProjects(projects, desiredFields))
.setPaging(Paging.newBuilder()
.setTotal(nbOfProjects)
.setPageIndex(page)
.setPageSize(pageSize))
.build();
writeProtobuf(result, request, response);
}
}

private static ComponentQuery buildDbQuery(@Nullable String nameOrKeyQuery) {
ComponentQuery.Builder dbQuery = ComponentQuery.builder()
.setQualifiers(Qualifiers.PROJECT)
.setOnProvisionedOnly(true);

ofNullable(nameOrKeyQuery).ifPresent(q -> {
dbQuery.setPartialMatchOnKey(true);
dbQuery.setNameOrKeyQuery(q);
});

return dbQuery.build();
}

private static List<Component> writeProjects(List<ComponentDto> projects, Set<String> desiredFields) {
return projects.stream().map(project -> {
Component.Builder compBuilder = Component.newBuilder().setUuid(project.uuid());
writeIfNeeded("key", project.getDbKey(), compBuilder::setKey, desiredFields);
writeIfNeeded("name", project.name(), compBuilder::setName, desiredFields);
writeIfNeeded("creationDate", project.getCreatedAt(), compBuilder::setCreationDate, desiredFields);
writeIfNeeded("visibility", project.isPrivate() ? PRIVATE.getLabel() : PUBLIC.getLabel(), compBuilder::setVisibility, desiredFields);
return compBuilder.build();
}).collect(toList());
}

private static void writeIfNeeded(String fieldName, String value, Consumer<String> setter, Set<String> desiredFields) {
if (desiredFields.contains(fieldName)) {
setter.accept(value);
}
}

private static void writeIfNeeded(String fieldName, @Nullable Date value, Consumer<String> setter, Set<String> desiredFields) {
if (desiredFields.contains(fieldName)) {
ofNullable(value).map(DateUtils::formatDateTime).ifPresent(setter);
}
}

private static Set<String> desiredFields(Request request) {
List<String> desiredFields = request.paramAsStrings(Param.FIELDS);
if (desiredFields == null) {
return POSSIBLE_FIELDS;
}

return newHashSet(desiredFields);
}
}

+ 0
- 17
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java View File

@@ -93,10 +93,6 @@ public class SearchAction implements ProjectsWsAction {
.setResponseExample(getClass().getResource("search-example.json"))
.setHandler(this);

action.setChangelog(
new Change("6.4", "The 'uuid' field is deprecated in the response"),
new Change("6.7.2", format("Parameters %s and %s accept maximum %d values", PARAM_PROJECTS, PARAM_PROJECT_IDS, DatabaseUtils.PARTITION_SIZE_FOR_ORACLE)));

action.createParam(Param.TEXT_QUERY)
.setDescription("Limit search to: <ul>" +
"<li>component names that contain the supplied string</li>" +
@@ -140,16 +136,6 @@ public class SearchAction implements ProjectsWsAction {
.setMaxValuesAllowed(DatabaseUtils.PARTITION_SIZE_FOR_ORACLE)
.setExampleValue(String.join(",", KEY_PROJECT_EXAMPLE_001, KEY_PROJECT_EXAMPLE_002));

action
.createParam(PARAM_PROJECT_IDS)
.setDescription("Comma-separated list of project ids")
.setSince("6.6")
// parameter added to match api/projects/bulk_delete parameters
.setDeprecatedSince("6.6")
// Limitation of ComponentDao#selectByQuery(), max 1000 values are accepted.
// Restricting size of HTTP parameter allows to not fail with SQL error
.setMaxValuesAllowed(DatabaseUtils.PARTITION_SIZE_FOR_ORACLE)
.setExampleValue(String.join(",", UUID_EXAMPLE_01, UUID_EXAMPLE_02));
}

@Override
@@ -169,7 +155,6 @@ public class SearchAction implements ProjectsWsAction {
.setAnalyzedBefore(request.param(PARAM_ANALYZED_BEFORE))
.setOnProvisionedOnly(request.mandatoryParamAsBoolean(PARAM_ON_PROVISIONED_ONLY))
.setProjects(request.paramAsStrings(PARAM_PROJECTS))
.setProjectIds(request.paramAsStrings(PARAM_PROJECT_IDS))
.build();
}

@@ -202,7 +187,6 @@ public class SearchAction implements ProjectsWsAction {
ofNullable(request.getAnalyzedBefore()).ifPresent(d -> query.setAnalyzedBefore(parseDateOrDateTime(d).getTime()));
query.setOnProvisionedOnly(request.isOnProvisionedOnly());
ofNullable(request.getProjects()).ifPresent(keys -> query.setComponentKeys(new HashSet<>(keys)));
ofNullable(request.getProjectIds()).ifPresent(uuids -> query.setComponentUuids(new HashSet<>(uuids)));

return query.build();
}
@@ -236,7 +220,6 @@ public class SearchAction implements ProjectsWsAction {

Component.Builder builder = Component.newBuilder()
.setOrganization(organization.getKey())
.setId(dto.uuid())
.setKey(dto.getDbKey())
.setName(dto.name())
.setQualifier(dto.qualifier())

+ 1
- 3
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java View File

@@ -69,7 +69,7 @@ public class SearchMyProjectsAction implements ProjectsWsAction {

@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction("search_my_projects")
context.createAction("search_my_projects")
.setDescription("Return list of projects for which the current user has 'Administer' permission. Maximum 1'000 projects are returned.")
.setResponseExample(getClass().getResource("search_my_projects-example.json"))
.addPagingParams(100, MAX_SIZE)
@@ -77,7 +77,6 @@ public class SearchMyProjectsAction implements ProjectsWsAction {
.setInternal(true)
.setHandler(this);

action.setChangelog(new Change("6.4", "The 'id' field is deprecated in the response"));
}

@Override
@@ -134,7 +133,6 @@ public class SearchMyProjectsAction implements ProjectsWsAction {
public Project apply(ComponentDto dto) {
Project.Builder project = Project.newBuilder();
project
.setId(dto.uuid())
.setKey(dto.getDbKey())
.setName(dto.name());
data.lastSnapshot(dto.uuid()).ifPresent(s -> {

+ 0
- 14
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchRequest.java View File

@@ -40,7 +40,6 @@ class SearchRequest {
private final String analyzedBefore;
private final boolean onProvisionedOnly;
private final List<String> projects;
private final List<String> projectIds;

public SearchRequest(Builder builder) {
this.organization = builder.organization;
@@ -52,7 +51,6 @@ class SearchRequest {
this.analyzedBefore = builder.analyzedBefore;
this.onProvisionedOnly = builder.onProvisionedOnly;
this.projects = builder.projects;
this.projectIds = builder.projectIds;
}

@CheckForNull
@@ -98,11 +96,6 @@ class SearchRequest {
return projects;
}

@CheckForNull
public List<String> getProjectIds() {
return projectIds;
}

public static Builder builder() {
return new Builder();
}
@@ -117,7 +110,6 @@ class SearchRequest {
private String analyzedBefore;
private boolean onProvisionedOnly = false;
private List<String> projects;
private List<String> projectIds;

public Builder setOrganization(@Nullable String organization) {
this.organization = organization;
@@ -164,14 +156,8 @@ class SearchRequest {
return this;
}

public Builder setProjectIds(@Nullable List<String> projectIds) {
this.projectIds = projectIds;
return this;
}

public SearchRequest build() {
checkArgument(projects==null || !projects.isEmpty(), "Project key list must not be empty");
checkArgument(projectIds==null || !projectIds.isEmpty(), "Project id list must not be empty");
checkArgument(pageSize == null || pageSize <= MAX_PAGE_SIZE, "Page size must not be greater than %s", MAX_PAGE_SIZE);
return new SearchRequest(this);
}

+ 8
- 27
server/sonar-server/src/main/java/org/sonar/server/project/ws/UpdateKeyAction.java View File

@@ -30,11 +30,8 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.server.component.ComponentService;
import org.sonar.server.exceptions.NotFoundException;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_UPDATE_KEY;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_FROM;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_TO;

public class UpdateKeyAction implements ProjectsWsAction {
@@ -54,36 +51,26 @@ public class UpdateKeyAction implements ProjectsWsAction {
public WebService.NewAction doDefine(WebService.NewController context) {
WebService.NewAction action = context.createAction(ACTION_UPDATE_KEY)
.setDescription("Update a project or module key and all its sub-components keys.<br>" +
"Either '%s' or '%s' must be provided.<br> " +
"Requires one of the following permissions: " +
"<ul>" +
"<li>'Administer System'</li>" +
"<li>'Administer' rights on the specified project</li>" +
"</ul>",
PARAM_FROM, PARAM_PROJECT_ID)
"Requires one of the following permissions: " +
"<ul>" +
"<li>'Administer System'</li>" +
"<li>'Administer' rights on the specified project</li>" +
"</ul>")
.setSince("6.1")
.setPost(true)
.setHandler(this);

action.setChangelog(
new Change("6.4", "Move from api/components/update_key to api/projects/update_key"),
new Change("7.1", "Ability to update key of a disabled module"));

action.createParam(PARAM_PROJECT_ID)
.setDescription("Project or module id")
.setDeprecatedKey("id", "6.4")
.setDeprecatedSince("6.4")
.setExampleValue(UUID_EXAMPLE_01);

action.createParam(PARAM_FROM)
.setDescription("Project or module key")
.setDeprecatedKey("key", "6.4")
.setRequired(true)
.setExampleValue("my_old_project");

action.createParam(PARAM_TO)
.setDescription("New component key")
.setRequired(true)
.setDeprecatedKey("newKey", "6.4")
.setExampleValue("my_new_project");

return action;
@@ -91,18 +78,12 @@ public class UpdateKeyAction implements ProjectsWsAction {

@Override
public void handle(Request request, Response response) throws Exception {
String uuid = request.param(PARAM_PROJECT_ID);
String key = request.param(PARAM_FROM);
String key = request.mandatoryParam(PARAM_FROM);
String newKey = request.mandatoryParam(PARAM_TO);
checkArgument(uuid != null ^ key != null, "Either '%s' or '%s' must be provided", PARAM_PROJECT_ID, PARAM_FROM);

try (DbSession dbSession = dbClient.openSession(false)) {
Optional<ComponentDto> component;
if (uuid != null) {
component = dbClient.componentDao().selectByUuid(dbSession, uuid);
} else {
component = dbClient.componentDao().selectByKey(dbSession, key);
}
component = dbClient.componentDao().selectByKey(dbSession, key);
if (!component.isPresent() || component.get().getMainBranchProjectUuid() != null) {
throw new NotFoundException("Component not found");
}

+ 0
- 2
server/sonar-server/src/main/resources/org/sonar/server/project/ws/search-example.json View File

@@ -7,7 +7,6 @@
"components": [
{
"organization": "my-org-1",
"id": "project-uuid-1",
"key": "project-key-1",
"name": "Project Name 1",
"qualifier": "TRK",
@@ -17,7 +16,6 @@
},
{
"organization": "my-org-1",
"id": "project-uuid-2",
"key": "project-key-2",
"name": "Project Name 1",
"qualifier": "TRK",

+ 0
- 2
server/sonar-server/src/main/resources/org/sonar/server/project/ws/search_my_projects-example.json View File

@@ -6,7 +6,6 @@
},
"projects": [
{
"id": "AU-Tpxb--iU5OvuD2FLy",
"key": "clang",
"name": "Clang",
"lastAnalysisDate": "2016-06-11T14:25:53+0000",
@@ -14,7 +13,6 @@
"links": []
},
{
"id": "AU-TpxcA-iU5OvuD2FLz",
"key": "net.java.openjdk:jdk7",
"name": "JDK 7",
"description": "JDK",

+ 0
- 21
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java View File

@@ -831,27 +831,6 @@ public class SearchActionTest {
.assertJson(this.getClass(), "paging_with_page_size_to_minus_one.json");
}

@Test
public void deprecated_paging() {
RuleDto rule = newRule();
OrganizationDto organization = db.organizations().insert(o -> o.setKey("my-org-1"));
ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto(organization, "PROJECT_ID").setDbKey("PROJECT_KEY"));
indexPermissions();
ComponentDto file = db.components().insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
for (int i = 0; i < 12; i++) {
IssueDto issue = newDto(rule, file, project).setAssigneeUuid(null);
dbClient.issueDao().insert(session, issue);
}
session.commit();
indexIssues();

ws.newRequest()
.setParam(PARAM_PAGE_INDEX, "2")
.setParam(PARAM_PAGE_SIZE, "9")
.execute()
.assertJson(this.getClass(), "deprecated_paging.json");
}

@Test
public void default_page_size_is_100() {
ws.newRequest()

+ 2
- 2
server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java View File

@@ -104,7 +104,7 @@ public class BulkDeleteActionTest {
ComponentDto toKeep = db.components().insertPrivateProject(defaultOrganization);

TestResponse result = ws.newRequest()
.setParam("projectIds", toDeleteInOrg1.uuid() + "," + toDeleteInOrg2.uuid())
.setParam(PARAM_PROJECTS, toDeleteInOrg1.getDbKey() + "," + toDeleteInOrg2.getDbKey())
.execute();

assertThat(result.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT);
@@ -135,7 +135,7 @@ public class BulkDeleteActionTest {
db.components().insertPrivateProject(org1);

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("At lease one parameter among analyzedBefore, projects, projectIds, and q must be provided");
expectedException.expectMessage("At lease one parameter among analyzedBefore, projects and q must be provided");

try {
ws.newRequest().execute();

+ 10
- 59
server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkUpdateKeyActionTest.java View File

@@ -58,7 +58,6 @@ import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_DRY_RUN;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_FROM;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_TO;

public class BulkUpdateKeyActionTest {
@@ -122,7 +121,7 @@ public class BulkUpdateKeyActionTest {
ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo"));
ComponentDto inactiveFile = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/InactiveFile.xoo").setEnabled(false));

BulkUpdateKeyWsResponse result = callByUuid(project.uuid(), FROM, TO);
BulkUpdateKeyWsResponse result = callByKey(project.getDbKey(), FROM, TO);

assertThat(result.getKeysCount()).isEqualTo(2);
assertThat(result.getKeysList()).extracting(Key::getKey, Key::getNewKey, Key::getDuplicate)
@@ -155,18 +154,6 @@ public class BulkUpdateKeyActionTest {
callByKey(branch.getDbKey(), FROM, TO);
}

@Test
public void fail_to_bulk_update_key_using_branch_uuid() {
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project);
userSession.addProjectPermission(UserRole.USER, project);

expectedException.expect(NotFoundException.class);
expectedException.expectMessage(String.format("Component id '%s' not found", branch.uuid()));

callByUuid(branch.uuid(), FROM, TO);
}

@Test
public void fail_to_bulk_if_a_component_already_exists_with_the_same_key() {
componentDb.insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("my_project"));
@@ -228,26 +215,17 @@ public class BulkUpdateKeyActionTest {
}

@Test
public void fail_if_uuid_nor_key_provided() {
expectedException.expect(IllegalArgumentException.class);

call(null, null, FROM, TO, false);
}

@Test
public void fail_if_uuid_and_key_provided() {
public void fail_if_key_not_provided() {
expectedException.expect(IllegalArgumentException.class);

ComponentDto project = insertMyProject();

call(project.uuid(), project.getDbKey(), FROM, TO, false);
call(null, FROM, TO, false);
}

@Test
public void fail_if_project_does_not_exist() {
expectedException.expect(NotFoundException.class);

callDryRunByUuid("UNKNOWN_UUID", FROM, TO);
callDryRunByKey("UNKNOWN_KEY", FROM, TO);
}

@Test
@@ -257,7 +235,7 @@ public class BulkUpdateKeyActionTest {

expectedException.expect(ForbiddenException.class);

callDryRunByUuid(project.uuid(), FROM, TO);
callDryRunByKey(project.getDbKey(), FROM, TO);
}

@Test
@@ -272,22 +250,6 @@ public class BulkUpdateKeyActionTest {
callByKey(branch.getDbKey(), FROM, TO);
}

@Test
public void fail_when_using_branch_uuid() {
ComponentDto project = db.components().insertMainBranch();
userSession.logIn().addProjectPermission(UserRole.USER, project);
ComponentDto branch = db.components().insertProjectBranch(project);

expectedException.expect(NotFoundException.class);
expectedException.expectMessage(String.format("Component id '%s' not found", branch.uuid()));

ws.newRequest()
.setParam(PARAM_PROJECT_ID, branch.uuid())
.setParam(PARAM_FROM, "my_")
.setParam(PARAM_TO, "my_new_")
.execute();
}

@Test
public void api_definition() {
WebService.Action definition = ws.getDef();
@@ -296,37 +258,26 @@ public class BulkUpdateKeyActionTest {
assertThat(definition.since()).isEqualTo("6.1");
assertThat(definition.key()).isEqualTo("bulk_update_key");
assertThat(definition.params())
.hasSize(5)
.hasSize(4)
.extracting(WebService.Param::key)
.containsOnlyOnce("projectId", "project", "from", "to", "dryRun");
.containsOnlyOnce("project", "from", "to", "dryRun");
}

private ComponentDto insertMyProject() {
return componentDb.insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey(MY_PROJECT_KEY));
}

private BulkUpdateKeyWsResponse callDryRunByUuid(@Nullable String uuid, @Nullable String from, @Nullable String to) {
return call(uuid, null, from, to, true);
}

private BulkUpdateKeyWsResponse callDryRunByKey(@Nullable String key, @Nullable String from, @Nullable String to) {
return call(null, key, from, to, true);
}

private BulkUpdateKeyWsResponse callByUuid(@Nullable String uuid, @Nullable String from, @Nullable String to) {
return call(uuid, null, from, to, false);
return call(key, from, to, true);
}

private BulkUpdateKeyWsResponse callByKey(@Nullable String key, @Nullable String from, @Nullable String to) {
return call(null, key, from, to, false);
return call(key, from, to, false);
}

private BulkUpdateKeyWsResponse call(@Nullable String uuid, @Nullable String key, @Nullable String from, @Nullable String to, @Nullable Boolean dryRun) {
private BulkUpdateKeyWsResponse call(@Nullable String key, @Nullable String from, @Nullable String to, @Nullable Boolean dryRun) {
TestRequest request = ws.newRequest();

if (uuid != null) {
request.setParam(PARAM_PROJECT_ID, uuid);
}
if (key != null) {
request.setParam(PARAM_PROJECT, key);
}

+ 17
- 34
server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java View File

@@ -99,7 +99,7 @@ public class CreateActionTest {
userSession.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization());

CreateWsResponse response = call(CreateRequest.builder()
.setKey(DEFAULT_PROJECT_KEY)
.setProjectKey(DEFAULT_PROJECT_KEY)
.setName(DEFAULT_PROJECT_NAME)
.build());

@@ -116,7 +116,7 @@ public class CreateActionTest {
userSession.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization());

CreateWsResponse response = call(CreateRequest.builder()
.setKey(DEFAULT_PROJECT_KEY)
.setProjectKey(DEFAULT_PROJECT_KEY)
.setName(DEFAULT_PROJECT_NAME)
.setBranch("origin/master")
.build());
@@ -126,30 +126,13 @@ public class CreateActionTest {
.containsOnly(DEFAULT_PROJECT_KEY + ":origin/master", DEFAULT_PROJECT_NAME, "TRK", "public");
}

@Test
public void create_project_with_deprecated_parameter() {
OrganizationDto organization = db.organizations().insert();
userSession.addPermission(PROVISION_PROJECTS, organization);

CreateWsResponse response = ws.newRequest()
.setMethod(POST.name())
.setParam("organization", organization.getKey())
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam(PARAM_NAME, DEFAULT_PROJECT_NAME)
.executeProtobuf(CreateWsResponse.class);

assertThat(response.getProject())
.extracting(Project::getKey, Project::getName, Project::getQualifier, Project::getVisibility)
.containsOnly(DEFAULT_PROJECT_KEY, DEFAULT_PROJECT_NAME, "TRK", "public");
}

@Test
public void apply_project_visibility_public() {
OrganizationDto organization = db.organizations().insert();
userSession.addPermission(PROVISION_PROJECTS, organization);

CreateWsResponse result = ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.setParam("organization", organization.getKey())
.setParam("visibility", "public")
@@ -164,7 +147,7 @@ public class CreateActionTest {
userSession.addPermission(PROVISION_PROJECTS, organization);

CreateWsResponse result = ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.setParam("organization", organization.getKey())
.setParam("visibility", PRIVATE.getLabel())
@@ -180,7 +163,7 @@ public class CreateActionTest {
userSession.addPermission(PROVISION_PROJECTS, organization);

CreateWsResponse result = ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.setParam("organization", organization.getKey())
.executeProtobuf(CreateWsResponse.class);
@@ -195,7 +178,7 @@ public class CreateActionTest {
userSession.addPermission(PROVISION_PROJECTS, organization);

CreateWsResponse result = ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.setParam("organization", organization.getKey())
.executeProtobuf(CreateWsResponse.class);
@@ -211,7 +194,7 @@ public class CreateActionTest {
.checkCanUpdateProjectVisibility(any(BillingValidations.Organization.class), eq(true));

CreateWsResponse result = ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.setParam("organization", organization.getKey())
.setParam("visibility", "public")
@@ -227,7 +210,7 @@ public class CreateActionTest {
String longName = Strings.repeat("a", 1_000);

ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", longName)
.setParam("organization", organization.getKey())
.executeProtobuf(CreateWsResponse.class);
@@ -244,7 +227,7 @@ public class CreateActionTest {
userSession.logIn(user).addPermission(PROVISION_PROJECTS, organization);

ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.setParam("organization", organization.getKey())
.executeProtobuf(CreateWsResponse.class);
@@ -262,7 +245,7 @@ public class CreateActionTest {
userSession.logIn(user).addPermission(PROVISION_PROJECTS, organization);

ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.setParam("organization", organization.getKey())
.executeProtobuf(CreateWsResponse.class);
@@ -282,7 +265,7 @@ public class CreateActionTest {
expectedException.expectMessage("This organization cannot use project private");

ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.setParam("organization", organization.getKey())
.setParam("visibility", "private")
@@ -299,7 +282,7 @@ public class CreateActionTest {

call(CreateRequest.builder()
.setOrganization(organization.getKey())
.setKey(DEFAULT_PROJECT_KEY)
.setProjectKey(DEFAULT_PROJECT_KEY)
.setName(DEFAULT_PROJECT_NAME)
.build());
}
@@ -312,7 +295,7 @@ public class CreateActionTest {
expectedException.expectMessage("Malformed key for Project: 'project Key'. It cannot be empty nor contain whitespaces.");

call(CreateRequest.builder()
.setKey("project Key")
.setProjectKey("project Key")
.setName(DEFAULT_PROJECT_NAME)
.build());
}
@@ -334,14 +317,14 @@ public class CreateActionTest {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The 'name' parameter is missing");

call(CreateRequest.builder().setKey(DEFAULT_PROJECT_KEY).build());
call(CreateRequest.builder().setProjectKey(DEFAULT_PROJECT_KEY).build());
}

@Test
public void fail_when_missing_create_project_permission() {
expectedException.expect(ForbiddenException.class);

call(CreateRequest.builder().setKey(DEFAULT_PROJECT_KEY).setName(DEFAULT_PROJECT_NAME).build());
call(CreateRequest.builder().setProjectKey(DEFAULT_PROJECT_KEY).setName(DEFAULT_PROJECT_NAME).build());
}

@Test
@@ -349,7 +332,7 @@ public class CreateActionTest {
userSession.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization());

String result = ws.newRequest()
.setParam("key", DEFAULT_PROJECT_KEY)
.setParam("project", DEFAULT_PROJECT_KEY)
.setParam("name", DEFAULT_PROJECT_NAME)
.execute().getInput();

@@ -401,7 +384,7 @@ public class CreateActionTest {
TestRequest httpRequest = ws.newRequest()
.setMethod(POST.name());
ofNullable(request.getOrganization()).ifPresent(org -> httpRequest.setParam("organization", org));
ofNullable(request.getKey()).ifPresent(key -> httpRequest.setParam("project", key));
ofNullable(request.getProjectKey()).ifPresent(key -> httpRequest.setParam("project", key));
ofNullable(request.getName()).ifPresent(name -> httpRequest.setParam("name", name));
ofNullable(request.getBranch()).ifPresent(branch -> httpRequest.setParam("branch", branch));
return httpRequest.executeProtobuf(CreateWsResponse.class);

+ 2
- 38
server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java View File

@@ -57,7 +57,6 @@ import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.server.component.TestComponentFinder.from;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.CONTROLLER;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_ID;

public class DeleteActionTest {

@@ -85,18 +84,6 @@ public class DeleteActionTest {
dbClient,
userSessionRule, projectLifeCycleListeners)));

@Test
public void organization_administrator_deletes_project_by_id() throws Exception {
ComponentDto project = componentDbTester.insertPrivateProject();
userSessionRule.logIn().addPermission(ADMINISTER, project.getOrganizationUuid());

WsTester.TestRequest request = newRequest().setParam(PARAM_PROJECT_ID, project.uuid());
call(request);

assertThat(verifyDeletedKey()).isEqualTo(project.getDbKey());
verify(projectLifeCycleListeners).onProjectsDeleted(singleton(Project.from(project)));
}

@Test
public void organization_administrator_deletes_project_by_key() throws Exception {
ComponentDto project = componentDbTester.insertPrivateProject();
@@ -108,17 +95,6 @@ public class DeleteActionTest {
verify(projectLifeCycleListeners).onProjectsDeleted(singleton(Project.from(project)));
}

@Test
public void project_administrator_deletes_the_project_by_uuid() throws Exception {
ComponentDto project = componentDbTester.insertPrivateProject();
userSessionRule.logIn().addProjectPermission(ADMIN, project);

call(newRequest().setParam(PARAM_PROJECT_ID, project.uuid()));

assertThat(verifyDeletedKey()).isEqualTo(project.getDbKey());
verify(projectLifeCycleListeners).onProjectsDeleted(singleton(Project.from(project)));
}

@Test
public void project_administrator_deletes_the_project_by_key() throws Exception {
ComponentDto project = componentDbTester.insertPrivateProject();
@@ -186,7 +162,7 @@ public class DeleteActionTest {
.addProjectPermission(UserRole.USER, project);
expectedException.expect(ForbiddenException.class);

call(newRequest().setParam(PARAM_PROJECT_ID, project.uuid()));
call(newRequest().setParam(PARAM_PROJECT, project.getDbKey()));
}

@Test
@@ -196,7 +172,7 @@ public class DeleteActionTest {
userSessionRule.anonymous();
expectedException.expect(UnauthorizedException.class);

call(newRequest().setParam(PARAM_PROJECT_ID, project.uuid()));
call(newRequest().setParam(PARAM_PROJECT, project.getDbKey()));
}

@Test
@@ -211,18 +187,6 @@ public class DeleteActionTest {
call(newRequest().setParam(PARAM_PROJECT, branch.getDbKey()));
}

@Test
public void fail_when_using_branch_uuid() throws Exception {
ComponentDto project = db.components().insertMainBranch();
userSessionRule.logIn().addProjectPermission(UserRole.USER, project);
ComponentDto branch = db.components().insertProjectBranch(project);

expectedException.expect(NotFoundException.class);
expectedException.expectMessage(String.format("Component id '%s' not found", branch.uuid()));

call(newRequest().setParam(PARAM_PROJECT_ID, branch.uuid()));
}

private String verifyDeletedKey() {
ArgumentCaptor<ComponentDto> argument = ArgumentCaptor.forClass(ComponentDto.class);
verify(componentCleanerService).delete(any(DbSession.class), argument.capture());

+ 0
- 282
server/sonar-server/src/test/java/org/sonar/server/project/ws/GhostsActionTest.java View File

@@ -1,282 +0,0 @@
/*
* 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.server.project.ws;

import java.util.function.Consumer;
import org.apache.commons.lang.StringUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.SnapshotTesting;
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.TestResponse;
import org.sonar.server.ws.WsActionTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.component.SnapshotDto.STATUS_PROCESSED;
import static org.sonar.db.component.SnapshotDto.STATUS_UNPROCESSED;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
import static org.sonar.test.JsonAssert.assertJson;

public class GhostsActionTest {

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
@Rule
public ExpectedException expectedException = ExpectedException.none();

private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
private DbClient dbClient = db.getDbClient();

private WsActionTester ws = new WsActionTester(new GhostsAction(dbClient, userSessionRule, defaultOrganizationProvider));

@Test
public void definition() {
WebService.Action action = ws.getDef();
assertThat(action.key()).isEqualTo("ghosts");
assertThat(action.description()).isEqualTo("List ghost projects.<br> " +
"With the current architecture, it's no more possible to have invisible ghost projects. Therefore, the web service is deprecated.<br> " +
"Requires 'Administer System' permission.");
assertThat(action.since()).isEqualTo("5.2");
assertThat(action.isInternal()).isFalse();
assertThat(action.deprecatedSince()).isEqualTo("6.6");

assertThat(action.params()).hasSize(5);

Param organization = action.param("organization");
assertThat(organization.description()).isEqualTo("Organization key");
assertThat(organization.since()).isEqualTo("6.3");
assertThat(organization.isRequired()).isFalse();
assertThat(organization.isInternal()).isTrue();
}

@Test
public void ghost_projects_without_analyzed_projects() {
OrganizationDto organization = db.organizations().insert();
ComponentDto ghost1 = insertGhostProject(organization);
ComponentDto ghost2 = insertGhostProject(organization);
ComponentDto activeProject = insertActiveProject(organization);
userSessionRule.logIn().addPermission(ADMINISTER, organization);

TestResponse result = ws.newRequest()
.setParam("organization", organization.getKey())
.execute();

String json = result.getInput();
assertJson(json).isSimilarTo("{" +
" \"projects\": [" +
" {" +
" \"uuid\": \"" + ghost1.uuid() + "\"," +
" \"key\": \"" + ghost1.getDbKey() + "\"," +
" \"name\": \"" + ghost1.name() + "\"," +
" \"visibility\": \"private\"" +
" }," +
" {" +
" \"uuid\": \"" + ghost2.uuid() + "\"," +
" \"key\": \"" + ghost2.getDbKey() + "\"," +
" \"name\": \"" + ghost2.name() + "\"," +
" \"visibility\": \"private\"" +
" }" +
" ]" +
"}");
assertThat(json).doesNotContain(activeProject.uuid());
}

@Test
public void ghost_projects_with_correct_pagination() {
OrganizationDto organization = db.organizations().insert();
for (int i = 1; i <= 10; i++) {
int count = i;
insertGhostProject(organization, dto -> dto.setDbKey("ghost-key-" + count));
}
userSessionRule.logIn().addPermission(ADMINISTER, organization);

TestResponse result = ws.newRequest()
.setParam("organization", organization.getKey())
.setParam(Param.PAGE, "3")
.setParam(Param.PAGE_SIZE, "4")
.execute();

String json = result.getInput();
assertJson(json).isSimilarTo("{" +
" \"p\": 3," +
" \"ps\": 4," +
" \"total\": 10" +
"}");
assertThat(StringUtils.countMatches(json, "ghost-key-")).isEqualTo(2);
}

@Test
public void ghost_projects_with_chosen_fields() {
OrganizationDto organization = db.organizations().insert();
insertGhostProject(organization);
userSessionRule.logIn().addPermission(ADMINISTER, organization);

TestResponse result = ws.newRequest()
.setParam("organization", organization.getKey())
.setParam(Param.FIELDS, "name")
.execute();

assertThat(result.getInput())
.contains("uuid", "name")
.doesNotContain("key")
.doesNotContain("creationDate");
}

@Test
public void ghost_projects_with_partial_query_on_name() {
OrganizationDto organization = db.organizations().insert();
insertGhostProject(organization, dto -> dto.setName("ghost-name-10"));
insertGhostProject(organization, dto -> dto.setName("ghost-name-11"));
insertGhostProject(organization, dto -> dto.setName("ghost-name-20"));

userSessionRule.logIn().addPermission(ADMINISTER, organization);

TestResponse result = ws.newRequest()
.setParam("organization", organization.getKey())
.setParam(Param.TEXT_QUERY, "name-1")
.execute();

assertThat(result.getInput())
.contains("ghost-name-10", "ghost-name-11")
.doesNotContain("ghost-name-2");
}

@Test
public void ghost_projects_with_partial_query_on_key() {
OrganizationDto organization = db.organizations().insert();
insertGhostProject(organization, dto -> dto.setDbKey("ghost-key-1"));

userSessionRule.logIn().addPermission(ADMINISTER, organization);

TestResponse result = ws.newRequest()
.setParam("organization", organization.getKey())
.setParam(Param.TEXT_QUERY, "GHOST-key")
.execute();

assertThat(result.getInput())
.contains("ghost-key-1");
}

@Test
public void does_not_return_branches() {
OrganizationDto organization = db.organizations().insert();
ComponentDto ghostProject = db.components().insertMainBranch(organization);
db.components().insertSnapshot(ghostProject, dto -> dto.setStatus("U"));
ComponentDto ghostBranchProject = db.components().insertProjectBranch(ghostProject);
userSessionRule.logIn().addPermission(ADMINISTER, organization);

TestResponse result = ws.newRequest()
.setParam("organization", organization.getKey())
.execute();

assertJson(result.getInput()).isSimilarTo("{" +
" \"projects\": [" +
" {" +
" \"uuid\": \"" + ghostProject.uuid() + "\"," +
" \"key\": \"" + ghostProject.getDbKey() + "\"," +
" \"name\": \"" + ghostProject.name() + "\"," +
" \"visibility\": \"private\"" +
" }" +
" ]" +
"}");
}

@Test
public void ghost_projects_base_on_json_example() {
OrganizationDto organization = db.organizations().insert();
ComponentDto hBaseProject = ComponentTesting.newPrivateProjectDto(organization, "ce4c03d6-430f-40a9-b777-ad877c00aa4d")
.setDbKey("org.apache.hbas:hbase")
.setName("HBase")
.setCreatedAt(DateUtils.parseDateTime("2015-03-04T23:03:44+0100"))
.setPrivate(false);
dbClient.componentDao().insert(db.getSession(), hBaseProject);
dbClient.snapshotDao().insert(db.getSession(), SnapshotTesting.newAnalysis(hBaseProject)
.setStatus(STATUS_UNPROCESSED));
ComponentDto roslynProject = ComponentTesting.newPrivateProjectDto(organization, "c526ef20-131b-4486-9357-063fa64b5079")
.setDbKey("com.microsoft.roslyn:roslyn")
.setName("Roslyn")
.setCreatedAt(DateUtils.parseDateTime("2013-03-04T23:03:44+0100"));
dbClient.componentDao().insert(db.getSession(), roslynProject);
dbClient.snapshotDao().insert(db.getSession(), SnapshotTesting.newAnalysis(roslynProject)
.setStatus(STATUS_UNPROCESSED));
db.getSession().commit();
userSessionRule.logIn().addPermission(ADMINISTER, organization);

TestResponse result = ws.newRequest()
.setParam("organization", organization.getKey())
.execute();

assertJson(result.getInput()).isSimilarTo(ws.getDef().responseExampleAsString());
}

@Test
public void throws_ForbiddenException_if_not_administrator_of_organization() {
userSessionRule.logIn();

expectedException.expect(ForbiddenException.class);
expectedException.expectMessage("Insufficient privileges");

ws.newRequest().execute();
}

@Test
public void fail_with_NotFoundException_when_organization_with_specified_key_does_not_exist() {
userSessionRule.logIn();

expectedException.expect(NotFoundException.class);
expectedException.expectMessage("No organization for key 'foo'");

ws.newRequest().setParam("organization", "foo").execute();
}

private ComponentDto insertGhostProject(OrganizationDto organization) {
return insertGhostProject(organization, dto -> {
});
}

private ComponentDto insertGhostProject(OrganizationDto organization, Consumer<ComponentDto> consumer) {
ComponentDto project = db.components().insertPrivateProject(organization, consumer);
db.components().insertSnapshot(project, dto -> dto.setStatus(STATUS_UNPROCESSED));
return project;
}

private ComponentDto insertActiveProject(OrganizationDto organization) {
ComponentDto project = db.components().insertPrivateProject(organization);
db.components().insertSnapshot(project, dto -> dto.setStatus(STATUS_PROCESSED));
return project;
}

}

+ 0
- 259
server/sonar-server/src/test/java/org/sonar/server/project/ws/IndexActionTest.java View File

@@ -1,259 +0,0 @@
/*
* 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.server.project.ws;

import java.util.Arrays;
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.user.UserDto;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;

import static java.util.Optional.ofNullable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
import static org.sonar.test.JsonAssert.assertJson;

public class IndexActionTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Rule
public UserSessionRule userSession = UserSessionRule.standalone();

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);

private DbClient dbClient = db.getDbClient();

private UserDto user;

private WsActionTester ws = new WsActionTester(new IndexAction(dbClient, userSession));

@Before
public void setUp() {
user = db.users().insertUser("john");
userSession.logIn(user);
}

@Test
public void search_all_projects() {
insertProjectsAuthorizedForUser(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-build-breaker-plugin").setName("Sonar Build Breaker Plugin"));

String result = call(null, null, null);

verifyResult(result, "search_projects.json");
}

@Test
public void search_projects_with_modules() {
ComponentDto project1 = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin");
ComponentDto project2 = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task");
insertProjectsAuthorizedForUser(project1, project2);
db.components().insertComponents(
newModuleDto(project1).setDbKey("org.jenkins-ci.plugins:sonar-common").setName("Common"),
newModuleDto(project2).setDbKey("org.codehaus.sonar-plugins:sonar-ant-db").setName("Ant DB"));

String result = call(null, null, true);

verifyResult(result, "search_projects_with_modules.json");
}

@Test
public void search_project_by_key() {
insertProjectsAuthorizedForUser(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-build-breaker-plugin").setName("Sonar Build Breaker Plugin"));

String result = call("org.jenkins-ci.plugins:sonar", null, null);

verifyResult(result, "search_project_by_key.json");
}

@Test
public void search_project_by_id() {
ComponentDto project = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin");
insertProjectsAuthorizedForUser(
project,
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-build-breaker-plugin").setName("Sonar Build Breaker Plugin"));

String result = call(Long.toString(project.getId()), null, null);

verifyResult(result, "search_project_by_id.json");
}

@Test
public void search_projects_by_name() {
insertProjectsAuthorizedForUser(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-build-breaker-plugin").setName("Sonar Build Breaker Plugin"));

String result = call(null, "Plu", null);

verifyResult(result, "search_projects_by_name.json");
}

@Test
public void search_projects_with_modules_by_name() {
ComponentDto project1 = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin");
ComponentDto project2 = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task");
insertProjectsAuthorizedForUser(project1, project2);
db.components().insertComponents(
newModuleDto(project1).setDbKey("org.jenkins-ci.plugins:sonar-common-db").setName("Jenkins Common DB"),
newModuleDto(project1).setDbKey("org.jenkins-ci.plugins:sonar-common-server").setName("Jenkins Common Server"),
newModuleDto(project2).setDbKey("org.codehaus.sonar-plugins:sonar-ant-db").setName("Ant DB"));

String result = call(null, "Com", true);

verifyResult(result, "search_projects_with_modules_by_name.json");
}

@Test
public void return_empty_list_when_no_project_match_search() {
insertProjectsAuthorizedForUser(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-build-breaker-plugin").setName("Sonar Build Breaker Plugin"));

String result = call(null, "Unknown", null);

verifyResult(result, "empty.json");
}

@Test
public void return_only_projects_authorized_for_user() {
insertProjectsAuthorizedForUser(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task"));
db.components()
.insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-build-breaker-plugin").setName("Sonar Build Breaker Plugin"));

String result = call(null, null, null);

verifyResult(result, "return_only_projects_authorized_for_user.json");
}

@Test
public void do_not_verify_permissions_if_user_is_root() {
ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("P1").setName("POne"));

String result = call(null, null, null);

userSession.setNonRoot();
assertThat(result).isEqualTo("[]");

userSession.setRoot();
result = call(null, null, null);
assertJson(result).isSimilarTo("[" +
" {" +
" \"id\":" + project.getId() + "," +
" \"k\":\"P1\"," +
" \"nm\":\"POne\"," +
" \"sc\":\"PRJ\"," +
" \"qu\":\"TRK\"" +
" }" +
"]");
}

@Test
public void does_not_return_branches_when_searching_all_components() {
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project);
userSession.setRoot();

String result = call(null, null, null);

assertJson(result).isSimilarTo("[" +
" {" +
" \"id\":" + project.getId() + "," +
" }" +
"]");
}

@Test
public void does_not_return_branches_when_searching_by_key() {
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project);
userSession.setRoot();

String result = call(branch.getDbKey(), null, null);

assertJson(result).isSimilarTo("[]");
}

@Test
public void test_example() {
insertProjectsAuthorizedForUser(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.jenkins-ci.plugins:sonar").setName("Jenkins Sonar Plugin"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-ant-task").setName("Sonar Ant Task"),
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("org.codehaus.sonar-plugins:sonar-build-breaker-plugin").setName("Sonar Build Breaker Plugin"));

String result = call(null, null, null);

assertJson(result).ignoreFields("id").isSimilarTo(ws.getDef().responseExampleAsString());
}

@Test
public void define_index_action() {
WebService.Action action = ws.getDef();
assertThat(action).isNotNull();
assertThat(action.responseExampleAsString()).isNotEmpty();
assertThat(action.params()).hasSize(8);
}

private String call(@Nullable String key, @Nullable String search, @Nullable Boolean subprojects) {
TestRequest httpRequest = ws.newRequest();
ofNullable(key).ifPresent(e2 -> httpRequest.setParam("key", e2));
ofNullable(search).ifPresent(e1 -> httpRequest.setParam("search", e1));
ofNullable(subprojects).ifPresent(e -> httpRequest.setParam("subprojects", Boolean.toString(e)));
return httpRequest.execute().getInput();
}

private void insertProjectsAuthorizedForUser(ComponentDto... projects) {
db.components().insertComponents(projects);
setBrowsePermissionOnUser(projects);
}

private void setBrowsePermissionOnUser(ComponentDto... projects) {
Arrays.stream(projects).forEach(project -> userSession.addProjectPermission(UserRole.USER, project));
}

private void verifyResult(String json, String expectedJsonFile) {
assertJson(json).ignoreFields("id").isSimilarTo(getClass().getResource(getClass().getSimpleName() + "/" + expectedJsonFile));
}
}

+ 2
- 2
server/sonar-server/src/test/java/org/sonar/server/project/ws/ProjectsWsModuleTest.java View File

@@ -36,7 +36,7 @@ public class ProjectsWsModuleTest {
public void verify_count_of_added_components_on_SonarQube() {
ComponentContainer container = new ComponentContainer();
new ProjectsWsModule(new ConfigurationBridge(settings)).configure(container);
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 15);
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 12);
}

@Test
@@ -45,7 +45,7 @@ public class ProjectsWsModuleTest {
settings.setProperty(ProcessProperties.Property.SONARCLOUD_ENABLED.getKey(), true);

new ProjectsWsModule(new ConfigurationBridge(settings)).configure(container);
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 14);
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 11);
}

}

+ 0
- 226
server/sonar-server/src/test/java/org/sonar/server/project/ws/ProvisionedActionTest.java View File

@@ -1,226 +0,0 @@
/*
* 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.server.project.ws;

import org.apache.commons.lang.StringUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.SnapshotTesting;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.BillingValidationsProxy;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
import static org.sonar.db.permission.OrganizationPermission.SCAN;
import static org.sonar.test.JsonAssert.assertJson;

public class ProvisionedActionTest {

private static final String PARAM_ORGANIZATION = "organization";

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
@Rule
public ExpectedException expectedException = ExpectedException.none();

private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
private DbClient dbClient = db.getDbClient();

private WsActionTester ws = new WsActionTester(
new ProvisionedAction(new ProjectsWsSupport(dbClient, defaultOrganizationProvider, mock(BillingValidationsProxy.class)), dbClient, userSessionRule));

@Test
public void definition() {
WebService.Action action = ws.getDef();

assertThat(action.description()).isEqualTo("Get the list of provisioned projects.<br> " +
"Web service is deprecated. Use api/projects/search instead, with onProvisionedOnly=true.<br> " +
"Require 'Create Projects' permission.");
assertThat(action.since()).isEqualTo("5.2");
assertThat(action.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactlyInAnyOrder(
tuple("6.4", "The 'uuid' field is deprecated in the response"),
tuple("6.4", "Paging response fields is now in a Paging object"));
assertThat(action.deprecatedSince()).isEqualTo("6.6");

assertThat(action.params()).hasSize(5);

Param organization = action.param(PARAM_ORGANIZATION);
assertThat(organization.description()).isEqualTo("The key of the organization");
assertThat(organization.isInternal()).isTrue();
assertThat(organization.isRequired()).isFalse();
assertThat(organization.since()).isEqualTo("6.3");
}

@Test
public void all_provisioned_projects_without_analyzed_projects() {
OrganizationDto org = db.organizations().insert();
ComponentDto analyzedProject = ComponentTesting.newPrivateProjectDto(org, "analyzed-uuid-1");
db.components().insertComponents(newProvisionedProject(org, "1"), newProvisionedProject(org, "2"), analyzedProject);
db.components().insertSnapshot(SnapshotTesting.newAnalysis(analyzedProject));
userSessionRule.logIn().addPermission(PROVISION_PROJECTS, org);

TestResponse result = ws.newRequest()
.setParam(PARAM_ORGANIZATION, org.getKey())
.execute();

String json = result.getInput();
assertJson(json)
.isSimilarTo("{" +
" \"projects\":[" +
" {" +
" \"uuid\":\"provisioned-uuid-1\"," +
" \"key\":\"provisioned-key-1\"," +
" \"name\":\"provisioned-name-1\"," +
" \"visibility\":\"private\"" +
" }," +
" {" +
" \"uuid\":\"provisioned-uuid-2\"," +
" \"key\":\"provisioned-key-2\"," +
" \"name\":\"provisioned-name-2\"," +
" \"visibility\":\"private\"" +
" }" +
" ]" +
"}");
assertThat(json).doesNotContain("analyzed-uuid-1");
}

@Test
public void provisioned_projects_with_correct_pagination() {
OrganizationDto org = db.organizations().insert();
for (int i = 1; i <= 10; i++) {
db.components().insertComponent(newProvisionedProject(org, String.valueOf(i)));
}
userSessionRule.logIn().addPermission(PROVISION_PROJECTS, org);

TestRequest request = ws.newRequest()
.setParam(PARAM_ORGANIZATION, org.getKey())
.setParam(Param.PAGE, "3")
.setParam(Param.PAGE_SIZE, "4");

String jsonOutput = request.execute().getInput();

assertThat(StringUtils.countMatches(jsonOutput, "provisioned-uuid-")).isEqualTo(2);
}

@Test
public void provisioned_projects_with_desired_fields() {
OrganizationDto organization = db.organizations().insert();
db.components().insertComponent(newProvisionedProject(organization, "1"));
userSessionRule.logIn().addPermission(PROVISION_PROJECTS, organization);

String jsonOutput = ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())
.setParam(Param.FIELDS, "key")
.execute().getInput();

assertThat(jsonOutput).contains("uuid", "key")
.doesNotContain("name")
.doesNotContain("creationDate");
}

@Test
public void provisioned_projects_with_query() {
OrganizationDto org = db.organizations().insert();
db.components().insertComponents(newProvisionedProject(org, "1"), newProvisionedProject(org, "2"));
userSessionRule.logIn().addPermission(PROVISION_PROJECTS, org);

String jsonOutput = ws.newRequest()
.setParam(PARAM_ORGANIZATION, org.getKey())
.setParam(Param.TEXT_QUERY, "PROVISIONED-name-2")
.execute().getInput();

assertThat(jsonOutput)
.contains("provisioned-name-2", "provisioned-uuid-2")
.doesNotContain("provisioned-uuid-1");
}

@Test
public void provisioned_projects_as_defined_in_the_example() {
OrganizationDto org = db.organizations().insert();
ComponentDto hBaseProject = ComponentTesting.newPrivateProjectDto(org, "ce4c03d6-430f-40a9-b777-ad877c00aa4d")
.setDbKey("org.apache.hbas:hbase")
.setName("HBase")
.setCreatedAt(DateUtils.parseDateTime("2015-03-04T23:03:44+0100"))
.setPrivate(false);
ComponentDto roslynProject = ComponentTesting.newPrivateProjectDto(org, "c526ef20-131b-4486-9357-063fa64b5079")
.setDbKey("com.microsoft.roslyn:roslyn")
.setName("Roslyn")
.setCreatedAt(DateUtils.parseDateTime("2013-03-04T23:03:44+0100"));
db.components().insertComponents(hBaseProject, roslynProject);
userSessionRule.logIn().addPermission(PROVISION_PROJECTS, org);

TestResponse result = ws.newRequest()
.setParam(PARAM_ORGANIZATION, org.getKey())
.execute();

assertJson(result.getInput()).isSimilarTo(ws.getDef().responseExampleAsString());
}

@Test
public void fail_when_not_enough_privileges() {
OrganizationDto organization = db.organizations().insert();
db.components().insertComponent(newProvisionedProject(organization, "1"));
userSessionRule.logIn().addPermission(SCAN, organization);

expectedException.expect(ForbiddenException.class);

ws.newRequest().execute();
}

@Test
public void fail_with_NotFoundException_when_organization_with_specified_key_does_not_exist() {
TestRequest request = ws.newRequest()
.setParam(PARAM_ORGANIZATION, "foo");
userSessionRule.logIn();

expectedException.expect(NotFoundException.class);
expectedException.expectMessage("No organization for key 'foo'");

request.execute();
}

private static ComponentDto newProvisionedProject(OrganizationDto organizationDto, String uuid) {
return ComponentTesting
.newPrivateProjectDto(organizationDto, "provisioned-uuid-" + uuid)
.setName("provisioned-name-" + uuid)
.setDbKey("provisioned-key-" + uuid);
}
}

+ 1
- 28
server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java View File

@@ -286,22 +286,6 @@ public class SearchActionTest {
.doesNotContain(sonarlint.getKey());
}

@Test
public void search_by_component_uuids() {
userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
ComponentDto jdk = db.components().insertPrivateProject();
ComponentDto sonarqube = db.components().insertPrivateProject();
ComponentDto sonarlint = db.components().insertPrivateProject();

SearchWsResponse result = call(SearchRequest.builder()
.setProjectIds(Arrays.asList(jdk.uuid(), sonarqube.uuid()))
.build());

assertThat(result.getComponentsList()).extracting(Component::getKey)
.containsExactlyInAnyOrder(jdk.getKey(), sonarqube.getKey())
.doesNotContain(sonarlint.getKey());
}

@Test
public void request_throws_IAE_if_more_than_1000_projects() {
expectedException.expect(IllegalArgumentException.class);
@@ -312,16 +296,6 @@ public class SearchActionTest {
.build());
}

@Test
public void request_throws_IAE_if_more_than_1000_project_ids() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("'projectIds' can contains only 1000 values, got 1001");

call(SearchRequest.builder()
.setProjectIds(Collections.nCopies(1_001, "foo"))
.build());
}

@Test
public void fail_when_not_system_admin() {
userSession.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
@@ -356,7 +330,7 @@ public class SearchActionTest {
assertThat(action.since()).isEqualTo("6.3");
assertThat(action.handler()).isEqualTo(ws.getDef().handler());
assertThat(action.params()).extracting(Param::key)
.containsExactlyInAnyOrder("organization", "q", "qualifiers", "p", "ps", "visibility", "analyzedBefore", "onProvisionedOnly", "projects", "projectIds");
.containsExactlyInAnyOrder("organization", "q", "qualifiers", "p", "ps", "visibility", "analyzedBefore", "onProvisionedOnly", "projects");
assertThat(action.responseExample()).isEqualTo(getClass().getResource("search-example.json"));

Param organization = action.param("organization");
@@ -443,7 +417,6 @@ public class SearchActionTest {
ofNullable(wsRequest.getVisibility()).ifPresent(v -> request.setParam(PARAM_VISIBILITY, v));
ofNullable(wsRequest.getAnalyzedBefore()).ifPresent(d -> request.setParam(PARAM_ANALYZED_BEFORE, d));
ofNullable(wsRequest.getProjects()).ifPresent(l1 -> request.setParam(PARAM_PROJECTS, String.join(",", l1)));
ofNullable(wsRequest.getProjectIds()).ifPresent(l -> request.setParam(PARAM_PROJECT_IDS, String.join(",", l)));
request.setParam(PARAM_ON_PROVISIONED_ONLY, String.valueOf(wsRequest.isOnProvisionedOnly()));
return request.executeProtobuf(SearchWsResponse.class);
}

+ 0
- 7
server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchMyProjectsActionTest.java View File

@@ -118,7 +118,6 @@ public class SearchMyProjectsActionTest {
SearchMyProjectsWsResponse result = callWs();

assertThat(result.getProjectsCount()).isEqualTo(1);
assertThat(result.getProjects(0).getId()).isEqualTo(jdk7.uuid());
}

@Test
@@ -148,8 +147,6 @@ public class SearchMyProjectsActionTest {
SearchMyProjectsWsResponse result = callWs();

assertThat(result.getProjectsCount()).isEqualTo(3);
assertThat(result.getProjectsList()).extracting(Project::getId)
.containsExactly(a_project.uuid(), b_project.uuid(), c_project.uuid());
}

@Test
@@ -181,7 +178,6 @@ public class SearchMyProjectsActionTest {
SearchMyProjectsWsResponse result = callWs();

assertThat(result.getProjectsCount()).isEqualTo(1);
assertThat(result.getProjects(0).getId()).isEqualTo(jdk7.uuid());
}

@Test
@@ -196,7 +192,6 @@ public class SearchMyProjectsActionTest {
SearchMyProjectsWsResponse result = callWs();

assertThat(result.getProjectsCount()).isEqualTo(1);
assertThat(result.getProjects(0).getId()).isEqualTo(jdk7.uuid());
}

@Test
@@ -227,7 +222,6 @@ public class SearchMyProjectsActionTest {
SearchMyProjectsWsResponse result = callWs();

assertThat(result.getProjectsCount()).isEqualTo(1);
assertThat(result.getProjects(0).getId()).isEqualTo(jdk7.uuid());
}

@Test
@@ -249,7 +243,6 @@ public class SearchMyProjectsActionTest {
SearchMyProjectsWsResponse result = callWs();

assertThat(result.getProjectsCount()).isEqualTo(3);
assertThat(result.getProjectsList()).extracting(Project::getId).containsOnly(jdk7.uuid(), cLang.uuid(), sonarqube.uuid());
}

@Test

+ 13
- 74
server/sonar-server/src/test/java/org/sonar/server/project/ws/UpdateKeyActionTest.java View File

@@ -44,7 +44,6 @@ import org.sonar.server.ws.WsActionTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_FROM;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_ID;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_TO;

public class UpdateKeyActionTest {
@@ -66,43 +65,19 @@ public class UpdateKeyActionTest {
ComponentDto project = insertProject();
userSessionRule.addProjectPermission(UserRole.ADMIN, project);

callByKey(project.getKey(), ANOTHER_KEY);
call(project.getKey(), ANOTHER_KEY);

assertThat(selectByKey(project.getKey()).isPresent()).isFalse();
assertThat(selectByKey(ANOTHER_KEY).get().uuid()).isEqualTo(project.uuid());
}

@Test
public void update_key_of_project_referenced_by_its_uuid() {
ComponentDto project = insertProject();
userSessionRule.addProjectPermission(UserRole.ADMIN, project);

callByUuid(project.uuid(), ANOTHER_KEY);

assertThat(selectByKey(project.getKey()).isPresent()).isFalse();
assertThat(selectByKey(ANOTHER_KEY).get().uuid()).isEqualTo(project.uuid());
}

@Test
public void update_key_of_module_referenced_by_its_uuid() {
ComponentDto project = insertProject();
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
userSessionRule.addProjectPermission(UserRole.ADMIN, project);

callByUuid(module.uuid(), ANOTHER_KEY);

assertThat(selectByKey(project.getKey()).isPresent()).isTrue();
assertThat(selectByKey(module.getKey()).isPresent()).isFalse();
assertThat(selectByKey(ANOTHER_KEY).get().uuid()).isEqualTo(module.uuid());
}

@Test
public void update_key_of_disabled_module() {
ComponentDto project = insertProject();
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project).setEnabled(false));
userSessionRule.addProjectPermission(UserRole.ADMIN, project);

callByKey(module.getKey(), ANOTHER_KEY);
call(module.getKey(), ANOTHER_KEY);

assertThat(selectByKey(project.getKey()).isPresent()).isTrue();
assertThat(selectByKey(module.getKey()).isPresent()).isFalse();
@@ -111,7 +86,6 @@ public class UpdateKeyActionTest {
assertThat(loadedModule.isEnabled()).isFalse();
}


@Test
public void fail_if_not_authorized() {
ComponentDto project = insertProject();
@@ -120,7 +94,7 @@ public class UpdateKeyActionTest {
expectedException.expect(ForbiddenException.class);
expectedException.expectMessage("Insufficient privileges");

callByKey(project.getKey(), ANOTHER_KEY);
call(project.getKey(), ANOTHER_KEY);
}

@Test
@@ -131,34 +105,22 @@ public class UpdateKeyActionTest {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The 'to' parameter is missing");

callByKey(project.getKey(), null);
call(project.getKey(), null);
}

@Test
public void fail_if_uuid_nor_key_provided() {
public void fail_if_key_not_provided() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Either 'projectId' or 'from' must be provided");
expectedException.expectMessage("The 'from' parameter is missing");

call(null, null, ANOTHER_KEY);
}

@Test
public void fail_if_both_uuid_and_key_provided() {
ComponentDto project = insertProject();
userSessionRule.addProjectPermission(UserRole.ADMIN, project);

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Either 'projectId' or 'from' must be provided");


call(project.uuid(), project.getKey(), ANOTHER_KEY);
call(null, ANOTHER_KEY);
}

@Test
public void fail_if_project_does_not_exist() {
expectedException.expect(NotFoundException.class);

callByUuid("UNKNOWN_UUID", ANOTHER_KEY);
call("UNKNOWN_UUID", ANOTHER_KEY);
}

@Test
@@ -170,19 +132,7 @@ public class UpdateKeyActionTest {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Component not found");

callByKey(branch.getDbKey(), ANOTHER_KEY);
}

@Test
public void fail_when_using_branch_uuid() {
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project);
userSessionRule.addProjectPermission(UserRole.ADMIN, project);

expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Component not found");

callByUuid(branch.uuid(), ANOTHER_KEY);
call(branch.getDbKey(), ANOTHER_KEY);
}

@Test
@@ -192,31 +142,20 @@ public class UpdateKeyActionTest {
assertThat(definition.since()).isEqualTo("6.1");
assertThat(definition.isPost()).isTrue();
assertThat(definition.key()).isEqualTo("update_key");
assertThat(definition.changelog()).hasSize(2);
assertThat(definition.changelog()).hasSize(1);
assertThat(definition.params())
.hasSize(3)
.hasSize(2)
.extracting(Param::key)
.containsOnlyOnce("projectId", "from", "to");
.containsOnlyOnce("from", "to");
}

private ComponentDto insertProject() {
return db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()));
}

private void callByUuid(@Nullable String uuid, @Nullable String newKey) {
call(uuid, null, newKey);
}

private void callByKey(@Nullable String key, @Nullable String newKey) {
call(null, key, newKey);
}

private String call(@Nullable String uuid, @Nullable String key, @Nullable String newKey) {
private String call(@Nullable String key, @Nullable String newKey) {
TestRequest request = ws.newRequest();

if (uuid != null) {
request.setParam(PARAM_PROJECT_ID, uuid);
}
if (key != null) {
request.setParam(PARAM_FROM, key);
}

+ 2
- 4
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ProjectsActionTest.java View File

@@ -355,10 +355,8 @@ public class ProjectsActionTest {
assertThat(definition.params()).extracting(Param::key).containsExactlyInAnyOrder("key", "p", "ps", "q", "selected");
Param profile = definition.param("key");
assertThat(profile.deprecatedKey()).isNullOrEmpty();
Param page = definition.param("p");
assertThat(page.deprecatedKey()).isEqualTo("page");
Param pageSize = definition.param("ps");
assertThat(pageSize.deprecatedKey()).isEqualTo("pageSize");
assertThat(definition.param("p")).isNotNull();
assertThat(definition.param("ps")).isNotNull();
Param query = definition.param("q");
assertThat(query.deprecatedKey()).isEqualTo("query");
}

+ 0
- 7
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/deprecated_paging.json View File

@@ -1,7 +0,0 @@
{
"paging": {
"pageIndex": 2,
"pageSize": 9,
"total": 12
}
}

+ 0
- 2
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java View File

@@ -378,13 +378,11 @@ public interface WebService extends Definable<WebService.Context> {
return createParam(Param.PAGE)
.setDescription(PAGE_PARAM_DESCRIPTION)
.setExampleValue("42")
.setDeprecatedKey("pageIndex", "5.2")
.setDefaultValue("1");
}

public NewParam createPageSize(int defaultPageSize, int maxPageSize) {
return createParam(Param.PAGE_SIZE)
.setDeprecatedKey("pageSize", "5.2")
.setDefaultValue(String.valueOf(defaultPageSize))
.setMaximumValue(maxPageSize)
.setDescription("Page size. Must be greater than 0 and less or equal than " + maxPageSize)

+ 0
- 15
sonar-ws/src/main/java/org/sonarqube/ws/client/projects/BulkDeleteRequest.java View File

@@ -34,7 +34,6 @@ public class BulkDeleteRequest {
private String analyzedBefore;
private String onProvisionedOnly;
private String organization;
private List<String> projectIds;
private List<String> projects;
private String q;
private List<String> qualifiers;
@@ -82,20 +81,6 @@ public class BulkDeleteRequest {
return organization;
}

/**
* Example value: "AU-Tpxb--iU5OvuD2FLy,AU-TpxcA-iU5OvuD2FLz"
* @deprecated since 6.4
*/
@Deprecated
public BulkDeleteRequest setProjectIds(List<String> projectIds) {
this.projectIds = projectIds;
return this;
}

public List<String> getProjectIds() {
return projectIds;
}

/**
* Example value: "my_project,another_project"
*/

+ 1
- 16
sonar-ws/src/main/java/org/sonarqube/ws/client/projects/BulkUpdateKeyRequest.java View File

@@ -19,7 +19,6 @@
*/
package org.sonarqube.ws.client.projects;

import java.util.List;
import javax.annotation.Generated;

/**
@@ -34,7 +33,6 @@ public class BulkUpdateKeyRequest {
private String dryRun;
private String from;
private String project;
private String projectId;
private String to;

/**
@@ -69,6 +67,7 @@ public class BulkUpdateKeyRequest {
}

/**
* This is a mandatory parameter.
* Example value: "my_old_project"
*/
public BulkUpdateKeyRequest setProject(String project) {
@@ -80,20 +79,6 @@ public class BulkUpdateKeyRequest {
return project;
}

/**
* Example value: "AU-Tpxb--iU5OvuD2FLy"
* @deprecated since 6.4
*/
@Deprecated
public BulkUpdateKeyRequest setProjectId(String projectId) {
this.projectId = projectId;
return this;
}

public String getProjectId() {
return projectId;
}

/**
* This is a mandatory parameter.
* Example value: "_new"

+ 0
- 14
sonar-ws/src/main/java/org/sonarqube/ws/client/projects/DeleteRequest.java View File

@@ -32,7 +32,6 @@ import javax.annotation.Generated;
public class DeleteRequest {

private String project;
private String projectId;

/**
* Example value: "my_project"
@@ -46,17 +45,4 @@ public class DeleteRequest {
return project;
}

/**
* Example value: "ce4c03d6-430f-40a9-b777-ad877c00aa4d"
* @deprecated since 6.4
*/
@Deprecated
public DeleteRequest setProjectId(String projectId) {
this.projectId = projectId;
return this;
}

public String getProjectId() {
return projectId;
}
}

+ 0
- 106
sonar-ws/src/main/java/org/sonarqube/ws/client/projects/GhostsRequest.java View File

@@ -1,106 +0,0 @@
/*
* 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.sonarqube.ws.client.projects;

import java.util.List;
import javax.annotation.Generated;

/**
* This is part of the internal API.
* This is a POST request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/projects/ghosts">Further information about this action online (including a response example)</a>
* @since 5.2
*/
@Generated("sonar-ws-generator")
public class GhostsRequest {

private List<String> f;
private String organization;
private String p;
private String ps;
private String q;

/**
* Possible values:
* <ul>
* <li>"name"</li>
* <li>"creationDate"</li>
* <li>"visibility"</li>
* <li>"uuid"</li>
* <li>"key"</li>
* </ul>
*/
public GhostsRequest setF(List<String> f) {
this.f = f;
return this;
}

public List<String> getF() {
return f;
}

/**
* This is part of the internal API.
*/
public GhostsRequest setOrganization(String organization) {
this.organization = organization;
return this;
}

public String getOrganization() {
return organization;
}

/**
* Example value: "42"
*/
public GhostsRequest setP(String p) {
this.p = p;
return this;
}

public String getP() {
return p;
}

/**
* Example value: "20"
*/
public GhostsRequest setPs(String ps) {
this.ps = ps;
return this;
}

public String getPs() {
return ps;
}

/**
* Example value: "sonar"
*/
public GhostsRequest setQ(String q) {
this.q = q;
return this;
}

public String getQ() {
return q;
}
}

+ 0
- 151
sonar-ws/src/main/java/org/sonarqube/ws/client/projects/IndexRequest.java View File

@@ -1,151 +0,0 @@
/*
* 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.sonarqube.ws.client.projects;

import java.util.List;
import javax.annotation.Generated;

/**
* This is part of the internal API.
* This is a POST request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/projects/index">Further information about this action online (including a response example)</a>
* @since 2.10
*/
@Generated("sonar-ws-generator")
public class IndexRequest {

private String desc;
private String format;
private String libs;
private String project;
private String search;
private String subprojects;
private String versions;
private String views;

/**
* @deprecated since 6.3
*/
@Deprecated
public IndexRequest setDesc(String desc) {
this.desc = desc;
return this;
}

public String getDesc() {
return desc;
}

/**
* Possible values:
* <ul>
* <li>"json"</li>
* </ul>
*/
public IndexRequest setFormat(String format) {
this.format = format;
return this;
}

public String getFormat() {
return format;
}

/**
* @deprecated since 6.3
*/
@Deprecated
public IndexRequest setLibs(String libs) {
this.libs = libs;
return this;
}

public String getLibs() {
return libs;
}

/**
* Example value: "my_project"
*/
public IndexRequest setProject(String project) {
this.project = project;
return this;
}

public String getProject() {
return project;
}

/**
* Example value: "Sonar"
*/
public IndexRequest setSearch(String search) {
this.search = search;
return this;
}

public String getSearch() {
return search;
}

/**
* Possible values:
* <ul>
* <li>"true"</li>
* <li>"false"</li>
* <li>"yes"</li>
* <li>"no"</li>
* </ul>
*/
public IndexRequest setSubprojects(String subprojects) {
this.subprojects = subprojects;
return this;
}

public String getSubprojects() {
return subprojects;
}

/**
* @deprecated since 6.3
*/
@Deprecated
public IndexRequest setVersions(String versions) {
this.versions = versions;
return this;
}

public String getVersions() {
return versions;
}

/**
* @deprecated since 6.3
*/
@Deprecated
public IndexRequest setViews(String views) {
this.views = views;
return this;
}

public String getViews() {
return views;
}
}

+ 0
- 71
sonar-ws/src/main/java/org/sonarqube/ws/client/projects/ProjectsService.java View File

@@ -54,7 +54,6 @@ public class ProjectsService extends BaseService {
.setParam("analyzedBefore", request.getAnalyzedBefore())
.setParam("onProvisionedOnly", request.getOnProvisionedOnly())
.setParam("organization", request.getOrganization())
.setParam("projectIds", request.getProjectIds() == null ? null : request.getProjectIds().stream().collect(Collectors.joining(",")))
.setParam("projects", request.getProjects() == null ? null : request.getProjects().stream().collect(Collectors.joining(",")))
.setParam("q", request.getQ())
.setParam("qualifiers", request.getQualifiers() == null ? null : request.getQualifiers().stream().collect(Collectors.joining(",")))
@@ -76,7 +75,6 @@ public class ProjectsService extends BaseService {
.setParam("dryRun", request.getDryRun())
.setParam("from", request.getFrom())
.setParam("project", request.getProject())
.setParam("projectId", request.getProjectId())
.setParam("to", request.getTo()),
BulkUpdateKeyWsResponse.parser());
}
@@ -110,73 +108,6 @@ public class ProjectsService extends BaseService {
call(
new PostRequest(path("delete"))
.setParam("project", request.getProject())
.setParam("projectId", request.getProjectId())
.setMediaType(MediaTypes.JSON)
).content();
}

/**
*
* This is part of the internal API.
* This is a GET request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/projects/ghosts">Further information about this action online (including a response example)</a>
* @since 5.2
* @deprecated since 6.6
*/
@Deprecated
public String ghosts(GhostsRequest request) {
return call(
new GetRequest(path("ghosts"))
.setParam("f", request.getF() == null ? null : request.getF().stream().collect(Collectors.joining(",")))
.setParam("organization", request.getOrganization())
.setParam("p", request.getP())
.setParam("ps", request.getPs())
.setParam("q", request.getQ())
.setMediaType(MediaTypes.JSON)
).content();
}

/**
*
* This is part of the internal API.
* This is a GET request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/projects/index">Further information about this action online (including a response example)</a>
* @since 2.10
* @deprecated since 6.3
*/
@Deprecated
public String index(IndexRequest request) {
return call(
new GetRequest(path("index"))
.setParam("desc", request.getDesc())
.setParam("format", request.getFormat())
.setParam("libs", request.getLibs())
.setParam("project", request.getProject())
.setParam("search", request.getSearch())
.setParam("subprojects", request.getSubprojects())
.setParam("versions", request.getVersions())
.setParam("views", request.getViews())
.setMediaType(MediaTypes.JSON)
).content();
}

/**
*
* This is part of the internal API.
* This is a GET request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/projects/provisioned">Further information about this action online (including a response example)</a>
* @since 5.2
* @deprecated since 6.6
*/
@Deprecated
public String provisioned(ProvisionedRequest request) {
return call(
new GetRequest(path("provisioned"))
.setParam("f", request.getF() == null ? null : request.getF().stream().collect(Collectors.joining(",")))
.setParam("organization", request.getOrganization())
.setParam("p", request.getP())
.setParam("ps", request.getPs())
.setParam("q", request.getQ())
.setMediaType(MediaTypes.JSON)
).content();
}
@@ -195,7 +126,6 @@ public class ProjectsService extends BaseService {
.setParam("onProvisionedOnly", request.getOnProvisionedOnly())
.setParam("organization", request.getOrganization())
.setParam("p", request.getP())
.setParam("projectIds", request.getProjectIds() == null ? null : request.getProjectIds().stream().collect(Collectors.joining(",")))
.setParam("projects", request.getProjects() == null ? null : request.getProjects().stream().collect(Collectors.joining(",")))
.setParam("ps", request.getPs())
.setParam("q", request.getQ())
@@ -230,7 +160,6 @@ public class ProjectsService extends BaseService {
call(
new PostRequest(path("update_key"))
.setParam("from", request.getFrom())
.setParam("projectId", request.getProjectId())
.setParam("to", request.getTo())
.setMediaType(MediaTypes.JSON)
).content();

+ 0
- 106
sonar-ws/src/main/java/org/sonarqube/ws/client/projects/ProvisionedRequest.java View File

@@ -1,106 +0,0 @@
/*
* 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.sonarqube.ws.client.projects;

import java.util.List;
import javax.annotation.Generated;

/**
* This is part of the internal API.
* This is a POST request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/projects/provisioned">Further information about this action online (including a response example)</a>
* @since 5.2
*/
@Generated("sonar-ws-generator")
public class ProvisionedRequest {

private List<String> f;
private String organization;
private String p;
private String ps;
private String q;

/**
* Possible values:
* <ul>
* <li>"name"</li>
* <li>"creationDate"</li>
* <li>"visibility"</li>
* <li>"uuid"</li>
* <li>"key"</li>
* </ul>
*/
public ProvisionedRequest setF(List<String> f) {
this.f = f;
return this;
}

public List<String> getF() {
return f;
}

/**
* This is part of the internal API.
*/
public ProvisionedRequest setOrganization(String organization) {
this.organization = organization;
return this;
}

public String getOrganization() {
return organization;
}

/**
* Example value: "42"
*/
public ProvisionedRequest setP(String p) {
this.p = p;
return this;
}

public String getP() {
return p;
}

/**
* Example value: "20"
*/
public ProvisionedRequest setPs(String ps) {
this.ps = ps;
return this;
}

public String getPs() {
return ps;
}

/**
* Example value: "sonar"
*/
public ProvisionedRequest setQ(String q) {
this.q = q;
return this;
}

public String getQ() {
return q;
}
}

+ 0
- 15
sonar-ws/src/main/java/org/sonarqube/ws/client/projects/UpdateKeyRequest.java View File

@@ -32,7 +32,6 @@ import javax.annotation.Generated;
public class UpdateKeyRequest {

private String from;
private String projectId;
private String to;

/**
@@ -47,20 +46,6 @@ public class UpdateKeyRequest {
return from;
}

/**
* Example value: "AU-Tpxb--iU5OvuD2FLy"
* @deprecated since 6.4
*/
@Deprecated
public UpdateKeyRequest setProjectId(String projectId) {
this.projectId = projectId;
return this;
}

public String getProjectId() {
return projectId;
}

/**
* This is a mandatory parameter.
* Example value: "my_new_project"

+ 0
- 2
sonar-ws/src/main/protobuf/ws-projects.proto View File

@@ -28,7 +28,6 @@ option optimize_for = SPEED;

message SearchMyProjectsWsResponse {
message Project {
optional string id = 1;
optional string key = 2;
optional string name = 4;
optional string description = 5;
@@ -66,7 +65,6 @@ message SearchWsResponse {

message Component {
optional string organization = 1;
optional string id = 2;
optional string key = 3;
optional string name = 4;
optional string qualifier = 5;

Loading…
Cancel
Save