@@ -60,6 +60,11 @@ public class ComponentDto implements Component { | |||
*/ | |||
private String kee; | |||
/** | |||
* Key of the root component this component belongs to. Consistent with projectUUid. | |||
*/ | |||
private String projectKey; | |||
/** | |||
* Not empty . Max size is 50 (note that effective UUID values are 40 characters with | |||
* the current algorithm in use). Obviously it is unique. | |||
@@ -221,6 +226,18 @@ public class ComponentDto implements Component { | |||
return this; | |||
} | |||
/** | |||
* Return the root project key. On a root project, return itself | |||
*/ | |||
public String projectKey() { | |||
return projectKey; | |||
} | |||
public ComponentDto setProjectKey(String projectKey) { | |||
this.projectKey = projectKey; | |||
return this; | |||
} | |||
public boolean isRoot() { | |||
return UUID_PATH_OF_ROOT.equals(uuidPath); | |||
} |
@@ -238,18 +238,21 @@ | |||
<select id="selectByQuery" resultType="Component"> | |||
select | |||
<include refid="componentColumns"/> | |||
<include refid="componentColumns"/>, | |||
root.kee as projectKey | |||
from projects p | |||
inner join projects root on p.project_uuid=root.uuid and p.organization_uuid=root.organization_uuid | |||
<include refid="sqlSelectByQuery"/> | |||
ORDER BY LOWER(p.name), p.name, p.id | |||
</select> | |||
<select id="countByQuery" resultType="int"> | |||
select count(p.id) | |||
from projects p | |||
<include refid="sqlSelectByQuery"/> | |||
</select> | |||
<sql id="sqlSelectByQuery"> | |||
from projects p | |||
where | |||
p.enabled=${_true} | |||
AND p.copy_component_uuid is null |
@@ -47,6 +47,7 @@ import static java.util.Collections.emptyList; | |||
import static java.util.Collections.emptySet; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.assertj.guava.api.Assertions.assertThat; | |||
import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
@@ -547,7 +548,8 @@ public class ComponentDaoTest { | |||
@Test | |||
public void select_provisioned() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto provisionedProject = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organization).setKey("provisioned.project").setName("Provisioned Project")); | |||
ComponentDto provisionedProject = db.components() | |||
.insertComponent(ComponentTesting.newPrivateProjectDto(organization).setKey("provisioned.project").setName("Provisioned Project")); | |||
ComponentDto provisionedView = db.components().insertView(organization); | |||
String projectUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization)).getComponentUuid(); | |||
String disabledProjectUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization).setEnabled(false)).getComponentUuid(); | |||
@@ -966,6 +968,23 @@ public class ComponentDaoTest { | |||
assertThat(underTest.selectByQuery(dbSession, allProjectsQuery, 0, 10)).extracting(ComponentDto::getKey).containsOnly("public-key", "private-key"); | |||
} | |||
@Test | |||
public void selectByQuery_returns_projectKey() { | |||
ComponentDto project = ComponentTesting.newPublicProjectDto(db.getDefaultOrganization()).setKey("project-key"); | |||
db.components().insertComponent(project); | |||
ComponentDto module = ComponentTesting.newModuleDto(project).setKey("module-key"); | |||
db.components().insertComponent(module); | |||
ComponentDto file = ComponentTesting.newFileDto(module).setKey("file-key"); | |||
db.components().insertComponent(file); | |||
ComponentQuery allQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT, Qualifiers.MODULE, Qualifiers.FILE).build(); | |||
assertThat(underTest.selectByQuery(dbSession, allQuery, 0, 10)).extracting(ComponentDto::getKey, ComponentDto::projectKey) | |||
.containsOnly(tuple("project-key", "project-key"), | |||
tuple("module-key", "project-key"), | |||
tuple("file-key", "project-key")); | |||
} | |||
@Test | |||
public void selectByQuery_on_empty_list_of_component_id() { | |||
ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT).setComponentIds(emptySet()).build(); |
@@ -46,8 +46,8 @@ import static com.google.common.base.Preconditions.checkArgument; | |||
import static org.sonar.core.util.Protobuf.setNullable; | |||
import static org.sonar.server.util.LanguageParamUtils.getExampleValue; | |||
import static org.sonar.server.util.LanguageParamUtils.getLanguageKeys; | |||
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | |||
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter; | |||
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_SEARCH; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_LANGUAGE; | |||
@@ -179,6 +179,7 @@ public class SearchAction implements ComponentsWsAction { | |||
.setOrganization(organization.getKey()) | |||
.setId(dto.uuid()) | |||
.setKey(dto.key()) | |||
.setProjectKey(dto.projectKey()) | |||
.setName(dto.name()) | |||
.setQualifier(dto.qualifier()); | |||
setNullable(dto.language(), builder::setLanguage); |
@@ -10,7 +10,8 @@ | |||
"id": "directory-uuid", | |||
"key": "directory-key", | |||
"qualifier": "DIR", | |||
"name": "Directory Name" | |||
"name": "Directory Name", | |||
"projectKey": "project-key" | |||
}, | |||
{ | |||
"organization": "my-org-1", | |||
@@ -18,21 +19,24 @@ | |||
"key": "file-key", | |||
"qualifier": "FIL", | |||
"name": "File Name", | |||
"language": "java" | |||
"language": "java", | |||
"projectKey": "project-key" | |||
}, | |||
{ | |||
"organization": "my-org-1", | |||
"id": "module-uuid", | |||
"key": "module-key", | |||
"qualifier": "BRC", | |||
"name": "Module Name" | |||
"name": "Module Name", | |||
"projectKey": "project-key" | |||
}, | |||
{ | |||
"organization": "my-org-1", | |||
"id": "project-uuid", | |||
"key": "project-key", | |||
"qualifier": "TRK", | |||
"name": "Project Name" | |||
"name": "Project Name", | |||
"projectKey": "project-key" | |||
} | |||
] | |||
} |
@@ -45,11 +45,14 @@ import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.MediaTypes; | |||
import org.sonarqube.ws.WsComponents.Component; | |||
import org.sonarqube.ws.WsComponents.SearchWsResponse; | |||
import org.sonarqube.ws.client.component.SearchWsRequest; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
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.mockito.Mockito.when; | |||
import static org.sonar.api.resources.Qualifiers.DIRECTORY; | |||
@@ -66,7 +69,6 @@ import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||
import static org.sonar.db.component.ComponentTesting.newView; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonarqube.ws.WsComponents.Component; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_LANGUAGE; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS; | |||
@@ -185,6 +187,25 @@ public class SearchActionTest { | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(file1.getKey(), file2.getKey()); | |||
} | |||
@Test | |||
public void return_project_key() throws IOException { | |||
ComponentDto project = ComponentTesting.newPublicProjectDto(db.getDefaultOrganization()); | |||
ComponentDto module = ComponentTesting.newModuleDto(project); | |||
ComponentDto file1 = newFileDto(module).setKey("file1"); | |||
ComponentDto file2 = newFileDto(module).setKey("file2"); | |||
ComponentDto file3 = newFileDto(project).setKey("file3"); | |||
db.components().insertComponents(project, module, file1, file2, file3); | |||
SearchWsResponse response = call(new SearchWsRequest().setQualifiers(asList(PROJECT, MODULE, FILE))); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey, Component::getProjectKey) | |||
.containsOnly(tuple(project.getKey(), project.getKey()), | |||
tuple(module.getKey(), project.getKey()), | |||
tuple(file1.getKey(), project.getKey()), | |||
tuple(file2.getKey(), project.getKey()), | |||
tuple(file3.getKey(), project.getKey())); | |||
} | |||
@Test | |||
public void do_not_verify_permissions_if_user_is_root() throws IOException { | |||
OrganizationDto org = db.organizations().insert(); |
@@ -118,6 +118,8 @@ message Component { | |||
optional Tags tags = 14; | |||
optional string visibility = 15; | |||
optional string leakPeriodDate = 16; | |||
// Root project key | |||
optional string projectKey = 17; | |||
message Tags { | |||
repeated string tags = 1; |